我正在 AWS 上构建我的应用程序,yy 应用程序使用如下 websocket:
前端 WebSocket 客户端 ---> AWS API Gateway Websocket API ----> EC2 实例中的后端
其工作原理如下:
使用 AWS API Gateway,WebSocket API 会执行我的
$connect
集成设置的操作。在我当前的配置中,我已在目标 URL 上设置了 VPC Link 与 HTTP Method Any 的集成。当前端尝试与 API 网关建立 WebSocket 连接时,将触发 WebSocket API 的 $connect
方法,并且 AWS WebSocket API 调用我的后端 HTTP 终端节点 <BACKEND_URL>/connect
。
前端:ReactJS / Javascript 本机 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 开发模式下,我可以看到以下错误消息:
虽然
\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"
}