在 React 中使用 ApolloClient 订阅 AppSync
Posted
技术标签:
【中文标题】在 React 中使用 ApolloClient 订阅 AppSync【英文标题】:AppSync subscriptions with ApolloClient in React 【发布时间】:2020-10-11 14:46:01 【问题描述】:我目前正在使用 ApolloClient 连接到 AppSync GraphQL API。这一切都非常适合查询和突变,但我在订阅工作时遇到了一些麻烦。我遵循了 Apollo 文档,我的 App.js 看起来像这样:
import React from 'react';
import './App.css';
import ApolloClient from 'apollo-client';
import ApolloProvider from '@apollo/react-hooks';
import InMemoryCache from 'apollo-cache-inmemory';
import ApolloLink, split from 'apollo-link';
import WebSocketLink from 'apollo-link-ws';
import getMainDefinition from 'apollo-utilities';
import createAuthLink from 'aws-appsync-auth-link';
import createHttpLink from 'apollo-link-http';
import AWSAppSyncClient, AUTH_TYPE from "aws-appsync";
import useSubscription from '@apollo/react-hooks';
import gql from 'apollo-boost';
const url = "https://xxx.appsync-api.eu-west-2.amazonaws.com/graphql"
const realtime_url = "wss://xxx.appsync-realtime-api.eu-west-2.amazonaws.com/graphql"
const region = "eu-west-2";
const auth =
type: AUTH_TYPE.API_KEY,
apiKey: process.env.REACT_APP_API_KEY
;
const wsLink = new WebSocketLink(
uri: realtime_url,
options:
reconnect: true
,
);
const link = split(
// split based on operation type
( query ) =>
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
,
ApolloLink.from([
createAuthLink( realtime_url, region, auth ),
wsLink
]),
ApolloLink.from([
createAuthLink( url, region, auth ),
createHttpLink( uri: url )
])
);
const client = new ApolloClient(
link: link,
cache: new InMemoryCache(
dataIdFromObject: object => object.id,
),
);
function Page()
const loading, error, data = useSubscription(
gql`
subscription questionReleased
questionReleased
id
released_date
`
)
if (loading) return <span>Loading...</span>
if (error) return <span>Error!</span>
if (data) console.log(data)
return (
<div>data</div>
);
function App()
return (
<ApolloProvider client=client>
<div className="App">
<Page />
</div>
</ApolloProvider>
);
export default App;
如果我在网络检查器中转到网络选项卡,我可以看到请求:
wss://xxx.appsync-realtime-api.eu-west-2.amazonaws.com/graphql
还有消息:
"type":"connection_init","payload":
"id":"1","type":"start","payload":"variables":,"extensions":,"operationName":"questionReleased","query":"subscription questionReleased \n questionReleased \n id\n released_date\n __typename\n \n\n"
"id":"2","type":"start","payload":"variables":,"extensions":,"operationName":"questionReleased","query":"subscription questionReleased \n questionReleased \n id\n released_date\n __typename\n \n\n"
"payload":"errors":["message":"Both, the \"header\", and the \"payload\" query string parameters are missing","errorCode":400],"type":"connection_error"
我搜索了很多,似乎 ApolloClient 可能与 AppSync 订阅不兼容 - 有人能够确认这一点吗?
因此,我尝试使用AWSAppSyncClient
进行订阅:
function Page()
const aws_client = new AWSAppSyncClient(
region: "eu-west-2",
url: realtime_url,
auth:
type: AUTH_TYPE.API_KEY,
apiKey: process.env.REACT_APP_API_KEY
,
disableOffline: true
);
const loading, error, data = useSubscription(
gql`
subscription questionReleased
questionReleased
id
released_date
`,
client: aws_client
)
if (loading) return <span>Loading...</span>
if (error) return <span>Error!</span>
if (data) console.log(data)
return (
<div>data</div>
);
它现在发送带有请求的查询字符串:
wss://xxx.appsync-realtime-api.eu-west-2.amazonaws.com/graphql?header=eyJob3N0I...&payload=e30=
我现在得到一个不同的错误:
"type":"connection_init"
"payload":"errors":["errorType":"HttpNotFoundException"],"type":"connection_error"
我已经仔细检查了 url,没关系(如果不是,你会得到ERR_NAME_NOT_RESOLVED
)。当我通过 AppSync 控制台手动运行订阅时,订阅有效,所以应该没问题。
我也在aws_client
上尝试过.hydrated()
,但又遇到了一个错误 (TypeError: this.refreshClient(...).client.subscribe is not a function
)
我做错了什么?这几天让我发疯了!
【问题讨论】:
【参考方案1】:发帖没多久,我终于想通了。我会把解决方案放在这里,以防其他人遇到同样的问题。首先AWSAppSyncClient
应该采用主要的graphql url 而不是实时url - 它可以自己计算出实时url。但是,我仍然无法使用 useSubscription
挂钩,只能通过调用 aws_client.subscribe()
。
为了让它与useSubscription
挂钩,我找到了这个讨论中提到的解决方案:
https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/450
具体如下: https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-no-offline-support
相关代码为:
import createSubscriptionHandshakeLink from 'aws-appsync-subscription-link';
const httpLink = createHttpLink( uri: url )
const link = ApolloLink.from([
createAuthLink( url, region, auth ),
createSubscriptionHandshakeLink(url, httpLink)
]);
使用它后,一切对我来说都很完美。
【讨论】:
这应该在 2021 年更新,以反映 AppSync 对 MQTT 支持的弃用。createSubscriptionHandshakeLink(url, httpLink)
将不再有效,您必须使用 createSubscriptionHandshakeLink( url, region, auth )
以上是关于在 React 中使用 ApolloClient 订阅 AppSync的主要内容,如果未能解决你的问题,请参考以下文章
React 和 ApolloClient:网络错误:forward(...).subscribe 不是函数
登录状态不会在 React、Apollo Client 2、Graphcool 中被动更新