graphql订阅返回空数据



这是我的问题,在我的react应用程序中,每当一个订单被创建时,我想为该订单获得一个名为orderNotification的订阅,

setup in order resolver:

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中都可以正常工作,但当我必须在组件中获取和显示结果时,返回的数据为null:

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}`)
})

解析订阅中的有效负载

Subscription: {
orderNotification: {
subscribe: (_, __, { pubsub }) => pubsub.asyncIterator(ORDER_NOTIFICATION),
resolve: (payload) => {
return payload;
},
}
}

另一种删除null或不需要的条目的方法是withFilter,用于在未知或不需要的事件时删除提示;

写这个答案作为一个意见,但上面的答案更好

const { withFilter } = require('graphql-subscriptions');
Subscription: {
orderNotification: {
subscribe: withFilter(
() => pubsub.asyncIterator('ORDER_NOTIFICATION'),
(payload, variables) => {
// add any condition here
return (payload && payload !== null);
},
),
},
}

最新更新