AWS API Gateway WebSocket:未选择代理集成并使用请求模板时连接失败

问题描述 投票:0回答:1

我正在 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}`);
    };

  }, [])

AWS WebSocket API 配置: enter image description here

后端: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
。 这是我的配置: enter image description here

但是,连接失败。我尝试将模板键设置为

\$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 开发模式下,我可以看到以下错误消息:

enter image description here

虽然

\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
1个回答
2
投票

回答自己,以防万一这可能对某人有帮助。

这其实是非常非常琐碎的事情。在将消息发送到客户端之前,我必须对从后端集成收到的响应配置模板化转换!

enter image description here

我将响应密钥配置为

$default
并且没有进一步的说明: enter image description here

而且它有效。

API Gateway 的 WebSocket API 似乎确实适合使用 Lambda 作为后端集成。

使用其他类型的后端集成,您将面临许多痛苦的问题,并且 AWS 文档/教程对于 Lambda 之外的后端集成类型完全没有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.