我正在将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.
晚了,但是试试这个
您应该按如下所示添加Cookies选项。请确保您的浏览器中有一个cookie,即csrftoken。它应该可用。希望它能工作。