【发布时间】:2020-06-03 19:03:49
【问题描述】:
我正在为我的网站使用 Next.js + react-apollo + apollo-server + express。最近我添加了 cookie 身份验证,因此必须在服务器中启用 CORS 才能使 cookie 身份验证工作。但是我看到阿波罗客户端查询在服务器端执行时会导致 http 500 状态。执行客户端成功解析时相同的查询。我很困惑,因为我实际上预计问题会发生在客户端,因为 CORS 在那里有更大的影响。我不确定是什么导致了问题,欢迎提出任何建议!
错误本身如下:
ApolloError:网络错误:请求https://example.com/graphql/ 失败,原因:写 EPROTO 140152723232576:error:14094410:SSL 例程:ssl3_read_bytes:sslv3 警报握手 失败:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL 警报编号 40
at new ApolloError (/src/node_modules/apollo-client/bundle.umd.js:92:26)
at /src/node_modules/apollo-client/bundle.umd.js:1588:34
at /src/node_modules/apollo-client/bundle.umd.js:2008:15
at Set.forEach (<anonymous>)
at /src/node_modules/apollo-client/bundle.umd.js:2006:26
at Map.forEach (<anonymous>)
at QueryManager.broadcastQueries (/src/node_modules/apollo-client/bundle.umd.js:2004:20)
at /src/node_modules/apollo-client/bundle.umd.js:1483:29
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
graphQLErrors: [],
networkError: FetchError: 请求https://example.com/graphql/ 失败,原因:写 EPROTO 140152723232576:error:14094410:SSL 例程:ssl3_read_bytes:sslv3 警报握手 失败:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL 警报编号 40
我使用的是 Amazon Cloudfront 提供的 SSL 证书。
这是我的客户端代码:
_app.js:
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
if (pageProps.errorStatusCode && ctx.res) {
ctx.res.statusCode = pageProps.errorStatusCode;
}
}
return { pageProps };
}
render() { //render... }
}
我有一个用于页面查询的 HOC:
const withQuery = (Page, query, variables, errorPolicy = 'none') => {
Page.getInitialProps = async ctx => {
const { apolloClient } = ctx;
try {
const { data } = await apolloClient.query({
query,
variables: vars,
errorPolicy
});
return { data };
} catch (error) {
return { errorStatusCode: error.networkError ? '500' : '404' };
}
};
// if (typeof window === 'undefined') { // THIS CODE IS CAUSING THE ISSUE
// return Page;
// }
}
这是我启动 apollo 客户端的方式:
import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from '../../fragmentTypes.json';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData
});
function createClient({ ctx, headers, initialState }) {
return new ApolloClient({
credentials: 'include',
uri: 'some_graphql_url',
cache: new InMemoryCache({ fragmentMatcher }).restore(initialState || {}),
headers
});
}
export default withApollo(createClient, { getDataFromTree: 'ssr' });
这是我的服务器代码:
import cors from 'cors'
const express = require('express')
const { ApolloServer } = require('apollo-server-express')
const { schema } = require('./models')
const server = new ApolloServer({
schema,
})
// required settings to accept cookies
const corsOptions = {
origin: function (origin, callback) {
if (corsWhitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true)
} else {
callback(new Error(`${origin} - not allowed by CORS`))
}
},
credentials: true
}
let app = express()
app.use(cors(corsOptions))
server.applyMiddleware({ app, cors: false })
const serverUrl = `my_server_url`
app.listen({ port }, () => console.log(`???? Server ready at ${serverUrl}`))
总结一下我的发现:
- 问题源于
_app.js调用await Component.getInitialProps(ctx)。 -
getInitialProps定义在withQueryHOC 中,查询由apolloClient.query方法执行。
没有 CORS 一切正常。
编辑:我注意到当 headers 选项与 CORS 一起添加到 createClient 时,问题将开始发生。
EDIT2:即使没有CORS也会发生错误,将headers选项添加到创建apollo客户端的createClient就足够了。
【问题讨论】:
-
我所知道的开始解决
500 Internal Server Error的唯一方法是查看服务器端日志文件。 -
@EternalHour 不,它没有。我在网站上从来没有遇到过 SSL 问题,所以它们只是在我添加 CORS 时才开始的。
-
问题中引用的错误消息似乎非常清楚地表明您在 SSL 错误中遇到的实际问题。我认为这里的任何其他人都无法猜到为什么在“添加 CORS”之后您可能会开始遇到 SSL 问题,但这仍然是 SSL 问题,而不是 CORS 问题。
标签: javascript ssl next.js apollo-client