graphql 订阅返回空数据

时间:2021-02-18 14:41:01

标签: reactjs graphql apollo-client apollo-server

这是我的问题,在我的反应应用程序中,每当创建订单时,我都想获得名为 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}`)
})

1 个答案:

答案 0 :(得分:0)

使用

解析订阅中的负载

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