authentication - 为什么我收到握手失败 Apollo 客户端错误(带有 EPROTO errno)?
问题描述
我正在使用apollo-boost: ^0.4.3
next.js。我最近在我的网站上添加了 cookie 身份验证。最大的变化是添加标题和credentials: 'include'
构造ApolloClient
函数。此外,在server.js
which starts express server for next.js 我添加了这个块:
const getServer = (isDevHttps, expressApp) => {
if (isDevHttps) {
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
const httpsServerOptions = {
key: fs.readFileSync(path.resolve('cert', 'localhost.key')),
cert: fs.readFileSync(path.resolve('cert', 'localhost.crt'))
};
console.info('creating https server');
return createServer(httpsServerOptions, expressApp);
}
return expressApp;
};
因为我需要在开发中运行 https。一切都在开发中工作(我使用https://localhost:3000作为客户端,使用https://localhost:443作为 graphql 后端服务器)。但是,当我将代码推送到 nginx 提供静态文件和 AWS 托管实例的暂存位置时,我开始收到此错误:
ApolloError: Network error: request to https://beta.leafreport.com/graphql/ failed, reason: write EPROTO 140426009438016:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1536:SSL alert number 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 runMicrotasks (<anonymous>)
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
graphQLErrors: [],
networkError: FetchError: request to https://staging.mysite.com/graphql/ failed, reason: write EPROTO 140426009438016:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../deps/openssl/openssl/ssl/record/rec_layer_s3.c:1536:SSL alert number 40
我第一次推送代码isDevHttps
时是true
错误的,NODE_TLS_REJECT_UNAUTHORIZED
被设置为 0。后来我确定了isDevHttps
它false
并重新部署。我们使用的 SSL 证书由 AWS Cloudfront 提供。
这是 Apollo 客户端的初始化代码:
import withApollo from 'next-with-apollo';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import { graphql_url } from 'my-config';
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: graphql_url,
cache: new InMemoryCache({ fragmentMatcher }).restore(initialState || {}),
headers
});
}
export default withApollo(createClient, { getDataFromTree: 'ssr' });
这是我的 package.json:
"dependencies": {
"@babel/runtime-corejs2": "^7.5.1",
"apollo-boost": "^0.4.3",
"apollo-mocked-provider": "^3.0.1",
"babel-eslint": "^10.0.2",
"body-parser": "^1.19.0",
"clean-css": "^4.2.1",
"compression": "^1.7.4",
"dotenv-load": "^2.0.0",
"graphql": "^14.3.1",
"graphql-tag": "^2.10.1",
"helmet": "^3.18.0",
"morgan": "^1.9.1",
"next": "^9.0.1",
"next-plugin-custom-babel-config": "^1.0.2",
"next-transpile-modules": "^2.3.1",
"next-with-apollo": "^4.2.0",
"nprogress": "^0.2.0",
"path": "^0.12.7",
"react-apollo": "^3.0.0",
"react-cookie-consent": "^2.5.0",
"react-google-login": "^3.2.1",
"react-facebook-login": "^4.0.1",
"react-minimal-pie-chart": "^4.2.0",
"react-motion-drawer": "^3.1.0",
"supports-webp": "^2.0.1",
"express-device": "^0.4.2"
}
这是nginx中的dev.conf(因为证书来自云端,所以ssl被注释掉是可以的):
server {
listen 80 default_server;
server_name staging.mysite.com;
include not_found.inc;
include static_resources.inc;
include ads.inc;
#include ssl.inc;
location / {
rewrite_log off;
include redirects/redirects.conf;
access_log /var/log/nginx/com-access.log combined;
error_log /var/log/nginx/com-error.log notice;
include graylog.logging;
include proxy_pass.inc;
auth_basic "closed site";
auth_basic_user_file /etc/nginx/.htpasswd;
}
}
在我的网站中,只有主页可以从服务器端运行,但其他页面都不能从服务器端运行,并从上面返回握手错误。主页是来自 Cloudfront 的更新。当点击链接客户端时,有些页面会打开,但是有些页面不会打开并导致 500 内部服务器错误(握手失败)。所以服务器端永远不会工作,但客户端有时会工作。
到目前为止,我尝试的任何方法都没有奏效,包括更改 AWS 实例、从 apollo 客户端构造函数中删除标头/凭据、多次重新部署。
我从错误堆栈中看到错误来自这里(node_modules/apollo-client/bundle.umd.js:92:26):
QueryManager.prototype.broadcastQueries = function () {
var _this = this;
this.onBroadcast();
this.queries.forEach(function (info, id) {
if (info.invalidated) {
info.listeners.forEach(function (listener) {
if (listener) {
listener(_this.queryStore.get(id), info.newData);
}
});
}
});
};
为什么客户端不能广播查询?
解决方案
推荐阅读
- java - 在画布中绘制一个矩形
- php - 如何让按钮在其自己的 div 中单击获取数据属性?
- javascript - 如何验证正则表达式本身是否有效?
- c# - 哪个结构更好,将事件处理程序作为 arg 传递,或监听事件触发?
- ios - 用于颤振的 GoogleMaps 插件仅显示 ios 模拟器上的标记
- php - 将数据作为数组传递 - PHP
- excel - SSRS 报告导出到 HH:mm:ss 格式的 excel 问题
- .net - 无法使用 office js 读取锁定的单元格值
- biztalk - BizTalk 中的 MSI 导出文件与预期不同
- windows - 如何在 Windows 中运行 json-server?