如何设置跨源cookie nextjs和apollo

时间:2019-08-13 10:21:05

标签: javascript cookies next.js react-apollo apollo-client

我的项目的前端和后端托管在单独的域中。当用户注册帐户时,会将cookie从服务器设置到包含userId的客户端计算机上。这在Google chrome和Firefox中没有问题,但是除非启用了第三方Cookie,否则在Safari上将无法工作。请求是通过阿波罗发送的,后端有一个graphql Yoga服务器。这是当前的配置:

前端:

import { ApolloLink, Observable, split } from 'apollo-link';
import { ApolloClient } from 'apollo-client';
import { BatchHttpLink } from 'apollo-link-batch-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { WebSocketLink } from 'apollo-link-ws';
import { createPersistedQueryLink } from 'apollo-link-persisted-queries';
import { getMainDefinition } from 'apollo-utilities';
import { onError } from 'apollo-link-error';
import withApollo from 'next-with-apollo';
import { withClientState } from 'apollo-link-state';
import { wss, endpoint } from '../config';

function createClient({ headers }) {
  const cache = new InMemoryCache();

  const request = async operation => {
    operation.setContext({
      http: {
        includeExtensions: true,
        includeQuery: false,
      },
      fetchOptions: {
        credentials: 'include',
      },
      headers,
    });
  };

  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();
        };
      })
  );

  const httpLink = new BatchHttpLink({
    uri: endpoint,
  });

  const wsLink = process.browser
    ? new WebSocketLink({
        uri: wss,
        options: {
          reconnect: true,
        },
      })
    : () => {
        console.log('SSR');
      };

  const terminatingLink = split(
    ({ query }) => {
      const { kind, operation } = getMainDefinition(query);
      return (
        kind === 'OperationDefinition' &&
        operation === 'subscription' &&
        process.browser
      );
    },
    wsLink,
    httpLink
  );

  return new ApolloClient({
    link: ApolloLink.from([
      onError(({ graphQLErrors, networkError }) => {
        if (graphQLErrors) {
          console.error({ graphQLErrors });
        }
        if (networkError) {
          console.error({ networkError });
        }
      }),
      requestLink,

      withClientState({
        defaults: {
          isConnected: true,
        },
        resolvers: {
          Mutation: {
            updateNetworkStatus: (_, { isConnected }, { cache }) => {
              cache.writeData({ data: { isConnected } });
              return null;
            },
          },
        },
        cache,
      }),

      createPersistedQueryLink().concat(terminatingLink),
    ]),
    cache,
  });
}

export default withApollo(createClient);

后端:


const cookieParser = require('cookie-parser');
const jwt = require('jsonwebtoken');
require('dotenv').config({ path: 'variables.env' });
const createServer = require('./createServer');
const db = require('./db');

const server = createServer();

server.express.use(cookieParser());
server.express.use((req, res, next) => {
  const { token } = req.cookies;
  if (token) {
    const { userId } = jwt.verify(token, process.env.APP_SECRET);
    req.userId = userId;
  }
  next();
});

server.express.use(async (req, res, next) => {
  if (!req.userId) return next();
  const user = await db.query.user(
    { where: { id: req.userId } },
    '{id, firstName, lastName, email}'
  );
  req.user = user;
  next();
});

server.start(
  {
    cors: {
      credentials: true,
      origin: process.env.FRONTEND_URL,
    },
    subscriptions: {
      keepAlive: true,
    },
  },
  s => {
    console.log('Server running!');
  }
);

从我看到的两端都设置了凭据的角度来看,请求以cookie响应,但Safari不会设置它。

Request Method: POST
Status Code: 200 OK
Remote Address: 10.22.179.204:80
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://www.rideout.rocks
Connection: keep-alive
Content-Length: 129
Content-Type: application/json
Date: Tue, 13 Aug 2019 10:17:07 GMT
Server: Cowboy
Vary: Origin
Via: 1.1 vegur
X-Powered-By: Express
Provisional headers are shown
accept: */*
content-type: application/json
Referer: https://www.rideout.rocks/
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36



Request URL: https://rideout-app-backend.herokuapp.com/
Request Method: POST
Status Code: 200 OK
Remote Address: 10.22.179.204:80
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://www.rideout.rocks
Connection: keep-alive
Content-Length: 537
Content-Type: application/json
Date: Tue, 13 Aug 2019 10:17:07 GMT
Server: Cowboy
Vary: Origin
Via: 1.1 vegur
X-Powered-By: Express
Provisional headers are shown
accept: */*
content-type: application/json
Referer: https://www.rideout.rocks/
Sec-Fetch-Mode: cors
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36```

Thanks for any insight and help.

0 个答案:

没有答案