graphql 订阅返回空数据
Posted
技术标签:
【中文标题】graphql 订阅返回空数据【英文标题】:graphql subscription return null data 【发布时间】:2021-05-21 12:53:07 【问题描述】:这是我的问题,在我的反应应用程序中,每当创建订单时,我都想获得该订单的订阅,称为 orderNotification,
在订单解析器中设置:
Subscription:
orderNotification:
subscribe: (_, __, pubsub ) => pubsub.asyncIterator(ORDER_NOTIFICATION)
变异:
Mutation:
async createOrder(_, MakeOrderInput: state, message, products, total , context)
try
const userAuth = isAuth(context);
const pubsub = context.pubsub;
const newOrder = new Order(
state,
username: userAuth.username,
user: userAuth.id,
createdAt: new Date().toISOString(),
total,
message,
products,
userAddress: userAuth.address,
);
const index = products.findIndex(x => x.cost === 0);
if (index != -1)
const u = await User.findById( _id: userAuth.id );
await User.findByIdAndUpdate( _id: userAuth.id , points: u.points - 20 , (err, data) =>
if (err)
console.log(err)
else
console.log('fatto')
);
const order = await newOrder.save();
pubsub.publish(ORDER_NOTIFICATION,
orderNotification: order
);
return order;
catch (err)
// throw new Error(err);
console.log(err)
,
在 graphql Playground 中一切正常,但是当我必须在我的组件中获取并显示结果时,返回的数据为空:
import React from 'react'
import gql from 'graphql-tag';
import useSubscription from '@apollo/client';
import Box from 'grommet'
function SubscriptionOrder()
const data, loading, error = useSubscription(SUBSCRIPTION_USER_ORDER,
onSubscriptionData: (d) => console.log(d),
onSubscriptionComplete: (da) => console.log(da)
);
// return null
// console.log(data)
return (
<>
<Box style= marginTop: '96px' >
data && data.orderNotification ? (
<h1>hi: data.orderNotification.username</h1>
) : (
<h1>NO DATA</h1>
)
</Box>
</>
)
;
const SUBSCRIPTION_USER_ORDER = gql`
subscription orderNotification
orderNotification
username
`;
export default SubscriptionOrder;
所以考虑到在操场上工作,错误可能在我的 ApolloClient 链接配置中:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import ApolloClient from 'apollo-client';
import ApolloProvider from '@apollo/react-hooks';
import InMemoryCache from 'apollo-cache-inmemory';
import HttpLink from 'apollo-link-http';
import onError from 'apollo-link-error';
import ApolloLink, Observable, split from 'apollo-link';
import WebSocketLink from 'apollo-link-ws';
import getMainDefinition from 'apollo-utilities';
import TokenRefreshLink from "apollo-link-token-refresh";
import jwtDecode from "jwt-decode";
import getAccessToken, setAccessToken from './accessToken';
import dotenv from 'dotenv/config.js'
const cache = new InMemoryCache();
const httpLink = new HttpLink(
uri: process.env.NODE_ENV === 'development' ? `$process.env.REACT_APP_SERVER_DEV/graphql` : `$process.env.REACT_APP_SERVER_PRODUCTION/graphql`,
credentials: "include",
);
const wsLink = new WebSocketLink(
uri: process.env.NODE_ENV === 'development' ? `ws://$process.env.REACT_APP_SERVER_DEV_WS/graphql` : `ws://$process.env.REACT_APP_SERVER_PRODUCTION_WS/graphql`,
options:
reconnect: true,
lazy: true,
inactivityTimeout: 1000,
,
connectionCallback: err =>
if (err)
console.log('Error Connecting to Subscriptions Server', err);
);
const splitLink = split(
( query ) =>
const kind, operation = getMainDefinition(query);
return kind === "OperationDefinition" && operation === "subscriptions";
,
wsLink,
httpLink
);
const requestLink = new ApolloLink(
(operation, forward) =>
new Observable(observer =>
let handle;
Promise.resolve(operation)
.then(operation =>
const accessToken = getAccessToken();
if (accessToken)
operation.setContext(
headers:
authorization: `Bearer $accessToken`
,
fetchOptions:
credentials: 'include'
);
)
.then(() =>
handle = forward(operation).subscribe(
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer)
);
)
.catch(observer.error.bind(observer));
return () =>
if (handle) handle.unsubscribe();
;
)
);
const client = new ApolloClient(
link: ApolloLink.from([
new TokenRefreshLink(
accessTokenField: "accessToken",
isTokenValidOrUndefined: () =>
const token = getAccessToken();
if (!token)
return true;
try
const exp = jwtDecode(token);
if (Date.now() >= exp * 1000)
return false;
else
return true;
catch
return false;
,
fetchAccessToken: () =>
return fetch(process.env.NODE_ENV === 'development' ? `$process.env.REACT_APP_SERVER_DEV/refresh_token` : `$process.env.REACT_APP_SERVER_PRODUCTION/refresh_token`,
method: "POST",
credentials: "include"
);
,
handleFetch: accessToken =>
setAccessToken(accessToken);
,
handleError: err =>
console.warn("Your refresh token is invalid. Try to relogin");
console.error(err);
),
onError(( graphQLErrors, networkError ) =>
console.log(graphQLErrors);
console.log(networkError);
),
requestLink,
splitLink,
]),
cache,
connectToDevTools: true,
credentials: 'include',
);
ReactDOM.render(
<React.StrictMode>
<ApolloProvider client=client>
<App />
</ApolloProvider>
</React.StrictMode >,
document.getElementById('root')
);
这是我的服务器:
import PubSub from 'graphql-subscriptions';
const pubsub = new PubSub();
const server = new ApolloServer(
typeDefs,
resolvers,
context: ( req, res ) => ( req, res, pubsub ),
introspection: true,
cors: corsOptions,
);
server.applyMiddleware( app, cors: false );
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
httpServer.listen(PORT, () =>
console.log(`???? Server ready at http://localhost:$PORT$server.graphqlPath`)
console.log(`???? Subscriptions ready at ws://localhost:$PORT$server.subscriptionsPath`)
)
【问题讨论】:
不查看代码...您在网络选项卡中看到了什么?检查地址/端口/协议/标头 在网络选项卡中,我看到了对 graphql 服务器的请求,其中有一个响应数据为空的订阅 没有认证用户?抛出错误而不是只记录?现在即使没有用户,您的代码也会继续 是的,当然有 auth 用户 问题是订阅只在操场上有效,useSubscription 挂钩仅在组件挂载时运行,并且每当我创建新订单时挂钩不会运行 【参考方案1】:解决订阅中的有效负载
Subscription:
orderNotification:
subscribe: (_, __, pubsub ) => pubsub.asyncIterator(ORDER_NOTIFICATION),
resolve: (payload) =>
return payload;
,
【讨论】:
以上是关于graphql 订阅返回空数据的主要内容,如果未能解决你的问题,请参考以下文章
当graphQL的查询从mongodb返回空数据时,你应该检查啥?
Apollo graphql 正在为 mongodb 中的空子文档返回空数据