AWS API Gatewayt WebSocket:集成后端中缺少转换后的请求模板请求正文

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

我正在 AWS 上构建我的应用程序,我的应用程序使用如下所示的 websocket:

前端 WebSocket 客户端 ---> AWS API Gateway Websocket API ----> EC2 实例中的后端。

现在,为了让我的后端 Express 代码知道如何向特定客户端发送消息,我让它知道 websocket 客户端/用户的

connectionId
。我正在关注这两个答案:

已经解释得很清楚了。

以下是我在 AWS API Gateway WebSocket API 中的配置:

我所做的是使用请求模板,匹配所有传入请求,来转换将作为请求正文发送到我的集成端点的内容。 最终我想保留原始请求,同时在其上添加属性(如连接 ID)。 为了测试目的,我设置了以下模板:

{
    "myConnectionId": "$context.connectionId",
    "body": "$context"
}

这有效,我可以在 AWS CloudWatch 中检查转换后的请求正文是

{
   "myConnectionId":"MFEdof95tjMCK0w=",
   "body":"{routeKey=$connect, disconnectStatusCode=null, messageId=null, eventType=CONNECT, extendedRequestId=MFEdoFJPtjMF64Q=, requestTime=17/Jan/2022:07:29:01 +0000, messageDirection=IN, disconnectReason=null, stage=production, connectedAt=1642404541417, requestTimeEpoch=1642404541418, identity={cognitoIdentityPoolId=null, cognitoIdentityId=null, principalOrgId=null, cognitoAuthenticationType=null, userArn=null, userAgent=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, accountId=null, caller=null, sourceIp=219.102.102.145, accessKey=null, cognitoAuthenticationProvider=null, user=null}, requestId=MFEdoFJPtjMF64Q=, domainName=123.execute-api.ap-northeast-1.amazonaws.com, connectionId=MFEdof95tjMCK0w=, apiId=hd5zymklr8}"
}

但是,在我的 EC2 实例中运行的 Express 后端中,即使触发了端点,请求正文还是空的,并且在其中找不到

myConnectionId

后端: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');
  });

日志输出:

2022-Jan-17 05:05:00:50  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 05:05:00:50  info: /connect _req.query: {}
2022-Jan-17 05:05:00:50  info: /connect _req.params: {}
2022-Jan-17 05:05:00:50  info: /connect _req.body: {}
2022-Jan-17 05:05:00:50  info: /connect _req.headers: {"x-amzn-apigateway-api-id":"hd5zymklr8","x-amzn-trace-id":"Root=1-61e5232c-626a05ff264650183a73c98a","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"}

请求确实发送到端点,但为什么请求体为空?

内容怎么丢失了?

node.js amazon-web-services websocket aws-api-gateway
2个回答
2
投票

我对此做了一些研究。

正如这篇文章中所讨论的:AWS API Gateway Websockets——connectionID 在哪里?,接受的答案(我在上面的问题中尝试的解决方案)假设您正在使用 Lambda 作为后端集成。

但是,我使用的是在 EC2 实例和 VPC Link 中运行的 Express JS。

就我而言,该问题实际上是由已投票的答案之一解决的(但不是已接受的答案):https://stackoverflow.com/a/65639742/3703783.

官方文档在这里:为 WebSocket API 设置数据映射

更新

上面的方法会将connectionId添加到集成请求的标头中,但是只有connectionId是不够的 - 我们还需要用户名之类的信息,以便后端能够知道在向特定的消息发送消息时使用哪个connectionId用户。这样就可以了:

aws apigatewayv2 update-integration 
--integration-id xxx 
--api-id xxx 
--request-parameters 'integration.request.header.userinfo'='route.request.body' 

另外,我还发现在我原来的问题中,而不是做

{
    "myConnectionId": "$context.connectionId",
    "body": "$context"
}

我应该简单地做:

{
  "integration.request.header.connectionId":"$context.connectionId",
}

这会将 ConnectionId 添加到请求标头中。


0
投票

我已经创建了集成请求模板,并且我能够在我的 VPC 终端节点中获取连接 ID -

模板键:

application/json

模板内容:

#set($connectionId = $context.connectionId)

{
  "connectionId": "$connectionId",
}
© www.soinside.com 2019 - 2024. All rights reserved.