繁体   English   中英

如何使用 AWS Websocket API Gateway Lambda 端点回调函数

[英]How to use AWS Websocket API Gateway Lambda endpoint callback function

当客户端向 AWS websocket API Gateway 发送 websocket 消息时,websocket Lambda 处理程序函数接收三个参数: eventcontextcallback

import type { APIGatewayProxyEvent, Context, } from "aws-lambda";

export class Handler {
  constructor() {}

  async execute(event: APIGatewayProxyEvent, context: Context, callback: any): Promise<void> {
    console.log(`${event}, ${context}, ${callback}`);

    if (!event.requestContext || !event.requestContext.connectionId) {
      callback(null, { statusCode: 400, body: "Missing RequestContext" });
    };

    callback(null, {statusCode: 200, body: 'Your message was received'});
  }
}

const Handler = new Handler(service);
async function handler(event: APIGatewayProxyEvent, context: Context, callback: any): Promise<void> {
  return await Handler.execute(event, context, callback);
}
export default handler;

处理程序检查它收到的event是否包含event.requestContext.connectionId的值。 如果没有,它调用回调函数传递null作为第一个参数和一条包含 400 statusCodebody的消息,其中消息告诉 connectionId 丢失:

callback(null, { statusCode: 400, body: "Missing RequestContext" });

不幸的是,我找不到任何描述我们应该如何使用这个callback函数的 AWS 文档。 相反,我使用了一些在 Internet 上找到的代码示例。

我期待调用callback函数并传递400 status将使 Handler 函数退出并引发异常。 但它不会发生。 处理程序只是继续执行下一行,就像什么都没发生一样,并且从未调用过回调函数。

  1. callback函数的真正目的是什么?
  2. 我们如何从 websocket 处理函数返回错误消息,让客户端应用程序知道发生的问题?
  3. 如果收到异常或无效参数,我们如何阻止 Handler 执行其余代码?
  4. websocket 处理程序应该返回任何值还是应该是无效的 - 没有返回值?

请将您的答案作为脚本示例或片段发布,以便我们对其进行测试。

PS 发布在https://aws.amazon.com/blogs/compute/announcing-websocket-apis-in-amazon-api-gateway/的文档说:

The backend can send messages to specific users via a callback URL that is provided after the user is connected to the WebSocket API.

并且有一个片段显示它:

exports.handler = function(event, context, callback) {
  var putParams = {
    TableName: process.env.TABLE_NAME,
    Item: {
      connectionId: { S: event.requestContext.connectionId }
    }
  };

  DDB.putItem(putParams, function(err, data) {
    callback(null, {
      statusCode: err ? 500 : 200,
      body: err ? "Failed to connect: " + JSON.stringify(err) : "Connected"
    });
  });
};

关于使用 Websocket API 的 Lambda 集成的双向通信模式,有一些重要的事情需要了解:

消除“回调”的歧义

“回调”是一个重载的术语。 首先,它指的是 Nodejs Lambda 函数处理程序的遗留模式。 我们应该考虑到这一点,以支持AWS 推荐的async-await 处理程序模式。 其次,AWS 有时将“回调 URL”称为后端使用@aws-sdk/client-apigatewaymanagementapi客户端1与 Websocket 客户端通信的方式。 文档还提到与@connections commands相同的东西。

您的代码的一个问题是您混淆了不相关的 Lambda 和 Websocket API“回调”概念。 为避免歧义,我将完全避免使用“回调”一词。

有 2 种双向通信模式

两种方法可以将数据从后端服务发送到连接的客户端:

方法 1: $default路由集成响应与RouteResponse

仅对于$default路由,您的 Lambda 可以在处理程序响应中向客户端返回一条消息。 这仅在您将RouteResponse添加到路线2时才有效。

// default-route-handler.ts
import { APIGatewayProxyWebsocketEventV2 } from 'aws-lambda';

interface TwoWayHandlerResponse {
  statusCode: 200 | 500;
  body: string;
}

export async function handler(event: APIGatewayProxyWebsocketEventV2): Promise<TwoWayHandlerResponse> {
  return {
    statusCode: 200,
    body: JSON.stringify('hello client, I am the $default route!'),
  };
}

方法二:@connections API

对于所有路由,您可以使用 @connections API 发送 POST 请求。 使用ApiGatewayManagementApi客户端的PostToConnection API 执行此操作,该 API 处理将消息发送到客户端的繁重工作。 Lambda 只是返回一个状态。

// another-great-handler.ts
import { APIGatewayProxyWebsocketEventV2 } from 'aws-lambda';
import { ApiGatewayManagementApiClient, PostToConnectionCommand } from '@aws-sdk/client-apigatewaymanagementapi';

interface StatusCodeResponse {
  statusCode: 200 | 500;
}

export async function handler(event: APIGatewayProxyWebsocketEventV2): Promise<StatusCodeResponse> {
  const { requestContext: { domainName, stage, connectionId, connectedAt, routeKey },} = event;

  try {
    const client = new ApiGatewayManagementApiClient({
      region: process.env.AWS_REGION,
      endpoint: 'https://' + domainName + '/' + stage,
    });

    const encoder = new TextEncoder();

    const postCmd = new PostToConnectionCommand({
      ConnectionId: connectionId,
      Data: encoder.encode(`Hello from ${routeKey}. You connected at: ${connectedAt}`),
    });

    await client.send(postCmd);
  } catch (err: unknown) {
    return { statusCode: 500 };
  }

  return { statusCode: 200 };
}

  1. 我正在使用AWS JS SDK v3

  2. 在控制台中添加一个 RouteResponse( $default route >“添加集成响应”按钮),或者使用create-route-response API,或者使用CloudFormation AWS::ApiGatewayV2::RouteResponse

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM