下一个js和Apollo-Cookie未通过

JavaScript React.js

小胖Gil

2020-03-20

我正在将Next JS与Apollo一起使用,并在with-data HOC中使用以下配置对其进行了设置:

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';
import { withClientState } from 'apollo-link-state';
import { getMainDefinition } from 'apollo-utilities';
import { ApolloLink, Observable, split  } from 'apollo-link';
import { WebSocketLink } from 'apollo-link-ws';
import withApollo from 'next-with-apollo';
import { SubscriptionClient } from 'subscriptions-transport-ws';

import { endpoint, prodEndpoint, WSendpoint, WSprodEndpoint } from '../config';

import defaults from '../apollo-state/graphql/default-state';
import Mutation from '../apollo-state/resolvers/mutation-resolvers';

const wsClient = process.browser ? new SubscriptionClient(process.env.NODE_ENV === 'development' ? WSendpoint : WSprodEndpoint, {
  reconnect: true,
}) : null;


function createClient({ headers }) {
  const wsLink = process.browser ? new WebSocketLink(wsClient) : null;
  const httpLink = new HttpLink({
    uri: process.env.NODE_ENV === 'development' ? endpoint : prodEndpoint,
    credentials: 'include',
  })

  const link = process.browser ? split(
    // split based on operation type
    ({ query }) => {
      const { kind, operation } = getMainDefinition(query);
      return kind === 'OperationDefinition' && operation === 'subscription';
    },
    wsLink,
    httpLink,
  ) : httpLink;

  const cache = new InMemoryCache();

  const request = async operation => {
    const contextObj = {
      fetchOptions: {
        credentials: 'include'
      },
      headers
    };
    operation.setContext(contextObj);
  }; 

  const requestLink = new ApolloLink((operation, forward) =>
    new Observable(observer => {
      let handle;
      Promise.resolve(operation)
        .then(oper => request(oper))
        .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();
      };
    })
  );
  // end custom config functions
  const apolloClient = new ApolloClient({
      credentials: 'include',
      ssrMode: !process.browser,
      link: ApolloLink.from([
        onError(({ graphQLErrors, networkError }) => {
          if (graphQLErrors) {
            console.log(graphQLErrors)
          }
          if (networkError) {
            console.log(networkError)
          }
        }),
        requestLink,
        withClientState({
          defaults, // default state
          resolvers: {
            Mutation // mutations
          },
          cache
        }),
        link
      ]),
      cache
  }); // end new apollo client
  return apolloClient;
}

export { wsClient };
export default withApollo(createClient);

在本地,一切正常。我可以登录,当我访问该站点时它会自动登录,并且SSR没问题。但是,当我部署到Next或Heroku时,SSR无法正常工作。

我调查了这个问题,似乎这是一个常见的问题,即未随请求一起发送Cookie:

https://github.com/apollographql/apollo-client/issues/4455

https://github.com/apollographql/apollo-client/issues/4190

https://github.com/apollographql/apollo-client/issues/4193

问题似乎在于Apollo配置的这一部分,其中有时未定义标头,因此未发送cookie:

  const request = async operation => {
    const contextObj = {
      fetchOptions: {
        credentials: 'include'
      },
      headers
    };
    operation.setContext(contextObj);
  }; 

人们提到的一些解决方法是:如果标题存在,则手动设置cookie标题:

  const request = async operation => {
    const contextObj = {
      fetchOptions: {
        credentials: 'include'
      },
      headers: {
        cookie: headers && headers.cookie
      }
    };
    operation.setContext(contextObj);
  }; 

The above amend to the code fixes the server side rendering however when I visit the site with a logged in cookie in my browser it will then no longer log me in automatically (it logs me in automatically with my initial method but wont do SSR on production)

People have mentioned it can be to do with Now or Heroku using a subdomain in the generated URLs you get once you deploy the app and to use a custom domain to resolve the issue. I tried using a custom domain however I am still experiencing the issue. My domain setup is like so:

Frontend domain: mysite.com backend domain: api.mysite.com

Has anyone here experienced the issue and been able to resolve it?

Please let me know if you spot something wrong with my config or how I have setup my domains.

第2532篇《下一个js和Apollo-Cookie未通过》来自Winter(https://github.com/aiyld/aiyld.github.io)的站点

1个回答
Gil伽罗小宇宙 2020.03.20

晚了,但是试试这个

您应该按如下所示添加Cookies选项。请确保您的浏览器中有一个cookie,即csrftoken。它应该可用。希望它能工作。


  const request =异步操作=> {
    const contextObj = {
      fetchOptions:{
        凭据:“包括”
      },
      // ################更改此处##########
      标头:{
        ...标题
      }
      饼干: {
        ...饼干
      }
      // #####################################

    };
    operation.setContext(contextObj);
  };

问题类别

JavaScript Ckeditor Python Webpack TypeScript Vue.js React.js ExpressJS KoaJS CSS Node.js HTML Django 单元测试 PHP Asp.net jQuery Bootstrap IOS Android