【发布时间】:2022-01-17 22:18:37
【问题描述】:
我正在 AWS 上构建我的应用程序,yy 应用程序使用 websocket,如下所示:
前端 WebSocket 客户端 ---> AWS API Gateway Websocket API ----> EC2 实例中的后端
这是它的工作原理:
借助 AWS API Gateway,WebSocket API 采取由我的 $connect 集成设置的操作。在我当前的配置中,我已在目标 url 上设置了与 HTTP Method Any 的 VPC Link 集成。当前端尝试与 API 网关建立 websocket 连接时,会触发 WebSocket API 的 $connect 方法,并且 AWS WebSocket API 会调用我的后端 HTTP 端点 <BACKEND_URL>/connect。
前端:ReactJS / Javascript Native Websocket: 在我使用 websocket 的组件中:
useEffect(() => {
const orgId = localData.get('currentOrganizationId');
const username = localData.get('username');
let socket = new WebSocket(process.env.REACT_APP_WEBSOCKET_URL); // this is the AWS WebSocket URL after I have deployed it.
socket.onopen = function(e) {
console.log('socket on onopen');
const info = JSON.stringify({orgId:orgId, username: username, action: "message"});
socket.send(info);
};
socket.onmessage = function(event) {
console.log(`[message] Data received from server: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
console.log(`[close] Connection died; code=${event.code}`);
}
};
socket.onerror = function(error) {
console.log(`[error] ${error.message}`);
};
}, [])
后端:NodeJS / ExpressJS,在index.ts:
app.get('/connect', function(_req, res) {
logger.info(`/connect _req: ${Object.keys(_req)}`);
logger.info(`/connect _req.query: ${JSON.stringify(_req.query)}`);
logger.info(`/connect _req.params: ${JSON.stringify(_req.params)}`);
logger.info(`/connect _req.body: ${JSON.stringify(_req.body)}`);
logger.info(`/connect _req.headers: ${JSON.stringify(_req.headers)}`);
res.send('/connect hahaha success');
});
app.put('/default', function(_req, res) {
logger.info(`/default _req.query: ${JSON.stringify(_req.query)}`);
logger.info(`/default _req.params: ${JSON.stringify(_req.params)}`);
logger.info(`/default _req.body: ${JSON.stringify(_req.body)}`);
logger.info(`/default _req.headers: ${JSON.stringify(_req.headers)}`);
res.send('/default hahaha default');
});
现在,这很完美。当我在浏览器中加载前端时,在 EC2 实例中,我可以看到 Express 的日志显示 \connect 已被触发,并且当 socket.onopen() 在前端代码中成功时会打印内容:
2022-Jan-17 11:51:29:5129 info: /connect _req: _readableState,_events,_eventsCount,_maxListeners,socket,httpVersionMajor,httpVersionMinor,httpVersion,complete,rawHeaders,rawTrailers,aborted,upgrade,url,method,statusCode,statusMessage,client,_consuming,_dumped,next,baseUrl,originalUrl,_parsedUrl,params,query,res,_startAt,_startTime,_remoteAddress,body,_parsedOriginalUrl,route
2022-Jan-17 11:51:29:5129 info: /connect _req.query: {}
2022-Jan-17 11:51:29:5129 info: /connect _req.params: {}
2022-Jan-17 11:51:29:5129 info: /connect _req.body: {}
2022-Jan-17 11:51:29:5129 info: /connect _req.headers: {"accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9","cache-control":"no-cache","origin":"http://127.0.0.1:3000","pragma":"no-cache","sec-websocket-extensions":"permessage-deflate; client_max_window_bits","sec-websocket-key":"w0HoFw7+RtvLi3KWgT2OBw==","sec-websocket-version":"13","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36","x-amzn-trace-id":"Root=1-61e4d9b1-671cf2d36097a75435133215","x-forwarded-for":"219.102.102.145","x-forwarded-port":"443","x-forwarded-proto":"https","x-amzn-apigateway-api-id":"hd5zymklr8","host":"NLB-docloud-internal-ea0692d1e2c8186c.elb.ap-northeast-1.amazonaws.com","connection":"Keep-Alive"}
2022-Jan-17 11:51:29:5129 info: /default _req.query: {}
2022-Jan-17 11:51:29:5129 info: /default _req.params: {}
2022-Jan-17 11:51:29:5129 info: /default _req.body: {"orgId":"1","username":"staff_a","action":"message"}
2022-Jan-17 11:51:29:5129 info: /default _req.headers: {"user-agent":"AmazonAPIGateway_hd5zymklr8","x-amzn-apigateway-api-id":"hd5zymklr8","host":"NLB-docloud-internal-ea0692d1e2c8186c.elb.ap-northeast-1.amazonaws.com","content-length":"53","content-type":"application/json; charset=UTF-8","connection":"Keep-Alive"}
另外,/default 会立即触发,并收到一条消息 {"orgId":"1","username":"staff_a","action":"message"},因为在我正在调用的前端代码中:
const info = JSON.stringify({orgId:orgId, username: username, action: "message"});
socket.send(info);
socket.onopen() 成功后立即。
到目前为止一切顺利。
现在,为了让我的后端 Express 代码知道如何向特定客户端发送消息,我让它知道 websocket 客户端/用户的connectionId。我正在关注这两个答案:
https://stackoverflow.com/a/59220644/3703783
https://stackoverflow.com/a/65112135/3703783
里面已经解释的很清楚了。
基本上我需要取消选择Use Proxy Integration并配置Request Templates。
这是我的配置:
但是,连接失败。我尝试将模板密钥设置为\$default 和$default,但它们都失败了。请注意,这不要与$default 路由混淆,在$connect 路由旁边。我们现在完全专注于 $connect 路由,它的请求模板键值恰好是 $default 以匹配所有请求。
Express 在 EC2 实例中的日志是:
2022-Jan-17 12:04:49:449 info: /connect _req: _readableState,_events,_eventsCount,_maxListeners,socket,httpVersionMajor,httpVersionMinor,httpVersion,complete,rawHeaders,rawTrailers,aborted,upgrade,url,method,statusCode,statusMessage,client,_consuming,_dumped,next,baseUrl,originalUrl,_parsedUrl,params,query,res,_startAt,_startTime,_remoteAddress,body,_parsedOriginalUrl,route
2022-Jan-17 12:04:49:449 info: /connect _req.query: {}
2022-Jan-17 12:04:49:449 info: /connect _req.params: {}
2022-Jan-17 12:04:49:449 info: /connect _req.body: {}
2022-Jan-17 12:04:49:449 info: /connect _req.headers: {"x-amzn-apigateway-api-id":"hd5zymklr8","x-amzn-trace-id":"Root=1-61e4dccd-254aa4f9581373b00f8ef54d","user-agent":"AmazonAPIGateway_hd5zymklr8","content-type":"application/json","accept":"application/json","host":"NLB-docloud-internal-ea0692d1e2c8186c.elb.ap-northeast-1.amazonaws.com","connection":"Keep-Alive"}
\connect 端点仍然像以前一样被触发,但是连接失败并且由于socket.onopen() 不成功,socket.send(info); 没有发送任何消息
在 chrome dev 模式下,我可以看到以下错误消息:
为什么\connect端点仍然像以前一样被触发,连接失败了?
我还注意到_req.headers 比以前短了很多:
{
"x-amzn-apigateway-api-id":"hd5zymklr8",
"x-amzn-trace-id":"Root=1-61e4dccd-254aa4f9581373b00f8ef54d",
"user-agent":"AmazonAPIGateway_hd5zymklr8",
"content-type":"application/json",
"accept":"application/json",
"host":"NLB-docloud-internal-ea0692d1e2c8186c.elb.ap-northeast-1.amazonaws.com",
"connection":"Keep-Alive"
}
一切顺利时的_req.headers:
{
"accept-encoding":"gzip, deflate, br",
"accept-language":"en-US,en;q=0.9",
"cache-control":"no-cache",
"origin":"http://127.0.0.1:3000",
"pragma":"no-cache",
"sec-websocket-extensions":"permessage-deflate; client_max_window_bits",
"sec-websocket-key":"w0HoFw7+RtvLi3KWgT2OBw==",
"sec-websocket-version":"13",
"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36",
"x-amzn-trace-id":"Root=1-61e4d9b1-671cf2d36097a75435133215",
"x-forwarded-for":"219.102.102.145",
"x-forwarded-port":"443",
"x-forwarded-proto":"https",
"x-amzn-apigateway-api-id":"hd5zymklr8",
"host":"NLB-docloud-internal-ea0692d1e2c8186c.elb.ap-northeast-1.amazonaws.com",
"connection":"Keep-Alive"
}
【问题讨论】:
标签: node.js reactjs amazon-web-services websocket aws-api-gateway