websockets

by Janitha Tennakoon

通过詹妮莎·特纳库恩

如何将WebSockets与AWS API Gateway和Lambda一起使用来构建实时应用程序 (How to build real-time applications using WebSockets with AWS API Gateway and Lambda)

Recently AWS has announced the launch of a widely-requested feature: WebSockets for Amazon API Gateway. With WebSockets, we are able to create a two-way communication line which can be used in many scenarios like real-time applications. This brings up the question: what are real-time applications? So let’s first answer that question.

最近,AWS宣布推出了一项广受欢迎的功能:用于Amazon API Gateway的WebSockets。 借助WebSocket,我们能够创建双向通信线路,该线路可用于许多场景,例如实时应用程序。 这就提出了一个问题:什么是实时应用程序? 因此,让我们首先回答这个问题。

Most of the applications that are currently operational use client-server architecture. In client-server architecture, the client sends the requests over the Internet using network communication and then the server processes that request and sends the response back to the client.

当前可运行的大多数应用程序都使用客户端-服务器体系结构。 在客户端-服务器体系结构中,客户端使用网络通信通过Internet发送请求,然后服务器处理该请求并将响应发送回客户端。

Here you can see that it is the client that starts off the communication with the server. So first the client initiates the communication and the server responds to the request sent by the server. So what if the server wants to start off the communication and push responses without the client requesting them first? That is where real-time applications come into the play.

在这里,您可以看到是客户端开始与服务器的通信。 因此,首先客户端启动通信,然后服务器响应服务器发送的请求。 那么,如果服务器要开始通信并推送响应而客户端不首先请求响应该怎么办? 这就是实时应用程序发挥作用的地方。

Real-time applications are applications where the server gets the ability to push to the clients without the client requesting data first. Assume we have a chat application where two chat clients can communicate via a server. In this situation, it is a waste if all the chat clients request data from the server like every second. What is more efficient is if the server sends data to client chat applications when a chat is received. This functionality can be done through real-time applications.

实时应用程序是服务器无需客户端先请求数据就可以推送到客户端的应用程序。 假设我们有一个聊天应用程序,其中两个聊天客户端可以通过服务器进行通信。 在这种情况下,如果所有聊天客户端都每秒都向服务器请求数据,那将是一种浪费。 更有效率的是,如果服务器在接收到聊天时将数据发送到客户端聊天应用程序。 此功能可以通过实时应用程序完成。

Amazon announced that they are going to support WebSockets in API Gateway at AWS re:Invent 2018. Later in December, they launched it in the API Gateway. So now using AWS infrastructure we are able to create real-time applications using API Gateway.

亚马逊宣布将在AWS re:Invent 2018上支持API Gateway中的WebSockets。12月下旬,他们在API Gateway中启动了WebSockets。 因此,现在使用AWS基础设施,我们可以使用API​​ Gateway创建实时应用程序。

In this post, we are going to create a simple chat application using API Gateway WebSockets. Before we start implementing our chat application, there are some concepts that we need to understand regarding real-time applications and API Gateway.

在本文中,我们将使用API​​ Gateway WebSockets创建一个简单的聊天应用程序。 在开始实现聊天应用程序之前,我们需要了解一些有关实时应用程序和API网关的概念。

WebSocket API概念 (WebSocket API Concepts)

A WebSocket API is composed of one or more routes. A route selection expression is there to determine which route a particular inbound request should use, which will be provided in the inbound request. The expression is evaluated against an inbound request to produce a value that corresponds to one of your route’s routeKey values. For example, if our JSON messages contain a property call action, and you want to perform different actions based on this property, your route selection expression might be ${request.body.action}.

WebSocket API由一个或多个路由组成。 路由选择表达式用于确定特定入站请求应使用的路由,该选择将在入站请求中提供。 根据入站请求对表达式进行求值,以生成与您的路线的routeKey值之一相对应的值。 例如,如果我们的JSON消息包含一个属性调用操作,并且您想基于此属性执行其他操作,则您的路线选择表达式可能是${request.body.action}

For example: if your JSON message looks like {“action” : “onMessage” , “message” : “Hello everyone”}, then the onMessage route will be chosen for this request.

例如:如果您的JSON消息看起来像{“ action”:“ onMessage”,“ message”:“大家好”},那么将为此请求选择onMessage路由。

By default, there are three routes which are already defined in the WebSocket API. In addition to the below-mentioned routes, we can add custom routes for our needs.

默认情况下,WebSocket API中已经定义了三种路由。 除了以下提到的路线外,我们还可以根据需要添加自定义路线。

  • $default — Used when the route selection expression produces a value that does not match any of the other route keys in your API routes. This can be used, for example, to implement a generic error handling mechanism.

    $ default —当路由选择表达式产生的值与API路由中的任何其他路由键都不匹配时使用。 例如,这可用于实现通用错误处理机制。

  • $connect — The associated route is used when a client first connects to your WebSocket API.

    $ connect —客户端第一次连接到WebSocket API时使用关联的路由。

  • $disconnect — The associated route is used when a client disconnects from your API.

    $ disconnect —当客户端从您的API断开连接时,将使用关联的路由。

Once a device is successfully connected through WebSocket API, the device will be allocated with a unique connection id. This connection id will be persisted throughout the lifetime if the connection. To send messages back to the device we need to use the following POST request using the connection id.

通过WebSocket API成功连接设备后,将为该设备分配唯一的连接ID。 如果建立连接,则该连接ID将在整个生命周期中保持不变。 要将消息发送回设备,我们需要使用以下带有连接ID的POST请求。

POST https://{api-id}.execute-api.us-east 1.amazonaws.com/{stage}/@connections/{connection_id}

实施聊天应用 (Implementing chat application)

After learning the basic concepts of the WebSocket API, let us look at how we can create a real-time application using WebSocket API. In this post, we are going to implement a simple chat application using WebSocket API, AWS LAmbda and DynamoDB. The following diagram shows the architecture of our real-time application.

在学习了WebSocket API的基本概念之后,让我们看一下如何使用WebSocket API创建实时应用程序。 在本文中,我们将使用WebSocket API,AWS LAmbda和DynamoDB实现一个简单的聊天应用程序。 下图显示了我们实时应用程序的体系结构。

In our application, devices will be connected to the API Gateway. When a device gets connected, a lambda function will save the connection id in a DynamoDB table. In an instance where we want to send a message back to the device, another lambda function will retrieve the connection id and POST data back to the device using a callback URL.

在我们的应用程序中,设备将连接到API网关。 连接设备后,lambda函数会将连接ID​​保存在DynamoDB表中。 在我们要将消息发送回设备的实例中,另一个lambda函数将使用回调URL检索连接ID和POST数据回到设备。

创建WebSocket API (Creating WebSocket API)

In order to create the WebSocket API, we need first go to Amazon API Gateway service using the console. In there choose to create new API. Click on WebSocket to create a WebSocket API, give an API name and our Route Selection Expression. In our case add $request.body.action as our selection expression and hit Create API.

为了创建WebSocket API,我们首先需要使用控制台进入Amazon API Gateway服务。 在其中选择创建新的API。 单击WebSocket创建一个WebSocket API,提供一个API名称和我们的路由选择表达式。 在本例中,将$ request.body.action添加为选择表达式,然后点击Create API。

After creating the API we will be redirected to the routes page. Here we can see already predefined three routes: $connect, $disconnect and $default. We will also create a custom route $onMessage. In our architecture, $connect and $disconnect routes achieve the following tasks:

创建API后,我们将被重定向到路由页面。 在这里,我们可以看到已经预定义的三个路由:$ connect,$ disconnect和$ default。 我们还将创建一个自定义路由$ onMessage。 在我们的体系结构中,$ connect和$ disconnect路由完成以下任务:

  • $connect — when this route is called, a Lambda function will add the connection id of the connected device to DynamoDB.$ connect —调用此路由时,Lambda函数会将已连接设备的连接ID添加到DynamoDB。
  • $disconnect — when this route is called, a Lambda function will delete the connection id of the disconnected device from DynamoDB.$ disconnect —调用此路由时,Lambda函数将从DynamoDB中删除断开连接的设备的连接ID。
  • onMessage — when this route is called, the message body will be sent to all the devices that are connected at the time.onMessage —调用此路由时,消息正文将发送到当时连接的所有设备。

Before adding the route according to the above, we need to do four tasks:

在根据上述步骤添加路由之前,我们需要完成以下四个任务:

  • Create a DynamoDB table创建一个DynamoDB表
  • Create connect lambda function创建连接lambda函数
  • Create disconnect lambda function创建断开连接lambda函数
  • Create onMessage lambda function创建onMessage lambda函数

First, let us create the DynamoDB table. Go to DynamoDB service and create a new table called Chat. Add primary key as ‘connectionid’.

首先,让我们创建DynamoDB表。 转到DynamoDB服务并创建一个名为Chat的新表。 将主键添加为“ connectionid”。

Next, let’s create the connect Lambda function. To create the Lambda function, go to Lambda services and click create function. Select Author from scratch and give the name as ‘ChatRoomConnectFunction’ and a role with necessary permissions. (The role should have the permission to get, put and delete items from DynamoDB, call API calls in API gateway.)

接下来,让我们创建connect Lambda函数。 要创建Lambda函数,请转到Lambda服务,然后单击创建函数。 从头开始选择“作者”,并将其命名为“ ChatRoomConnectFunction”,并指定一个具有必要权限的角色。 (该角色应具有从DynamoDB获取,放置和删除项目,在API网关中调用API调用的权限。)

In the code of the lambda function add the following code. This code will add the connection id of the connected device to the DynamoDB table that we have created.

在lambda函数的代码中添加以下代码。 此代码会将已连接设备的连接ID添加到我们创建的DynamoDB表中。

exports.handler = (event, context, callback) => {    const connectionId = event.requestContext.connectionId;    addConnectionId(connectionId).then(() => {    callback(null, {        statusCode: 200,        })    });}
function addConnectionId(connectionId) {    return ddb.put({        TableName: 'Chat',        Item: {            connectionid : connectionId        },    }).promise();}

Next, let us create the disconnect lambda function as well. Using the same steps create a new lambda function named ‘ChatRoomDonnectFunction’. Add the following code to the function. This code will remove the connection id from the DynamoDB table when a device gets disconnected.

接下来,让我们也创建断开连接lambda函数。 使用相同的步骤创建一个名为“ ChatRoomDonnectFunction”的新lambda函数。 将以下代码添加到函数中。 当设备断开连接时,此代码将从DynamoDB表中删除连接ID。

const AWS = require('aws-sdk');const ddb = new AWS.DynamoDB.DocumentClient();
exports.handler = (event, context, callback) => {    const connectionId = event.requestContext.connectionId;    addConnectionId(connectionId).then(() => {    callback(null, {        statusCode: 200,        })    });}
function addConnectionId(connectionId) {    return ddb.delete({        TableName: 'Chat',        Key: {            connectionid : connectionId,        },    }).promise();}

Now we have created the DynamoDB table and two lambda functions. Before creating the third lambda function, let us go back again to API Gateway and configure the routes using our created lambda functions. First, click on $connect route. As integration type, select Lambda function and select the ChatRoomConnectionFunction.

现在,我们已经创建了DynamoDB表和两个lambda函数。 在创建第三个lambda函数之前,让我们再次回到API网关,并使用创建的lambda函数配置路由。 首先,单击$ connect路由。 作为集成类型,选择Lambda函数,然后选择ChatRoomConnectionFunction。

We can do the same on $disconnect route as well where the lambda function will be ChatRoomDisconnectionFunction:

我们也可以在$ disconnect路由上执行相同的操作,其中lambda函数将是ChatRoomDisconnectionFunction:

Now that we have configured our $connect and $disconnect routes, we can actually test whether out WebSocket API is working. To do that we must first to deploy the API. In the Actions button, click on Deploy API to deploy. Give a stage name such as Test since we are only deploying the API for testing.

现在,我们已经配置了$ connect和$ disconnect路由,我们实际上可以测试WebSocket API是否有效。 为此,我们必须首先部署API。 在“操作”按钮中,单击“部署API”以进行部署。 由于我们仅部署API进行测试,因此请提供一个阶段名称(例如Test)。

After deploying, we will be presented with two URLs. The first URL is called WebSocket URL and the second is called Connection URL.

部署后,我们将看到两个URL。 第一个URL称为WebSocket URL,第二个称为Connection URL。

The WebSocket URL is the URL that is used to connect through WebSockets to our API by devices. And the second URL, which is Connection URL, is the URL which we will use to call back to the devices which are connected. Since we have not yet configured call back to devices, let’s first only test the $connect and $disconnect routes.

WebSocket URL是用于设备通过WebSocket连接到我们的API的URL。 第二个URL,即连接URL,是我们将用于回调已连接设备的URL。 由于尚未配置回叫设备,因此我们首先仅测试$ connect和$ disconnect路由。

To call through WebSockets we can use the wscat tool. To install it, we need to just issue the npm install -g wscat command in the command line. After installing, we can use the tool using wscat command. To connect to our WebSocket API, issue the following command. Make sure to replace the WebSocket URL with the correct URL provided to you.

要通过WebSocket调用,我们可以使用wscat工具。 要安装它,我们只需要在命令行中发出npm install -g wscat命令即可。 安装后,我们可以使用wscat命令使用该工具。 要连接到我们的WebSocket API,请发出以下命令。 确保使用提供给您的正确URL替换WebSocket URL。

wscat -c wss://bh5a9s7j1e.execute-api.us-east-1.amazonaws.com/Test

When the connection is successful, a connected message will be displayed on the terminal. To check whether our lambda function is working, we can go to DynamoDB and look in the table for the connection id of the connected terminal.

连接成功后,连接的消息将显示在终端上。 要检查我们的lambda函数是否正常工作,我们可以转到DynamoDB并在表中查找已连接终端的连接ID。

As above, we can test the disconnect as well by pressing CTRL + C which will simulate a disconnection.

如上所述,我们也可以通过按CTRL + C来测试断开连接,这将模拟断开连接。

Now that we have tested our two routes, let us look into the custom route onMessage. What this custom route will do is it will get a message from the device and send the message to all the devices that are connected to the WebSocket API. To achieve this we are going to need another lambda function which will query our DynamoDB table, get all the connection ids, and send the message to them.

现在我们已经测试了两条路由,让我们研究自定义路由onMessage。 该自定义路由将要执行的操作是,它将从设备获取消息,并将该消息发送到连接到WebSocket API的所有设备。 为此,我们将需要另一个lambda函数,该函数将查询我们的DynamoDB表,获取所有连接ID,并将消息发送给它们。

Let’s first create the lambda function in the same way we created other two lambda functions. Name the lambda function ChatRoomOnMessageFunction and copy the following code to the function code.

首先,以创建其他两个lambda函数的相同方式创建lambda函数。 将lambda函数命名为ChatRoomOnMessageFunction,然后将以下代码复制到该函数代码中。

const AWS = require('aws-sdk');const ddb = new AWS.DynamoDB.DocumentClient();require('./patch.js');
let send = undefined;function init(event) {  console.log(event)    const apigwManagementApi = new AWS.ApiGatewayManagementApi({    apiVersion: '2018-11-29',    endpoint: event.requestContext.domainName + '/' + event.requestContext.stage  });        send = async (connectionId, data) => {  await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: `Echo: ${data}` }).promise();  }}
exports.handler =  (event, context, callback) => {  init(event);  let message = JSON.parse(event.body).message    getConnections().then((data) => {        console.log(data.Items);        data.Items.forEach(function(connection) {           console.log("Connection " +connection.connectionid)           send(connection.connectionid, message);        });    });        return {}};
function getConnections(){    return ddb.scan({        TableName: 'Chat',    }).promise();}

The above code will scan the DynamoDB to get all the available records in the table. For each record, it will POST a message using the Connection URL provided to us in the API. In the code, we expect that the devices will send the message in the attribute named ‘message’ which the lambda function will parse and send to others.

上面的代码将扫描DynamoDB以获取表中所有可用的记录。 对于每条记录,它将使用API​​中提供给我们的连接URL发布消息。 在代码中,我们期望设备将在名为“ message”的属性中发送消息,lambda函数将解析该消息并将其发送给其他人。

Since WebSockets API is still new there are some things we need to do manually. Create a new file named patch.js and add the following code inside it.

由于WebSockets API仍然是新的,因此我们需要手动执行一些操作。 创建一个名为patch.js的新文件,并在其中添加以下代码。

require('aws-sdk/lib/node_loader');var AWS = require('aws-sdk/lib/core');var Service = AWS.Service;var apiLoader = AWS.apiLoader;
apiLoader.services['apigatewaymanagementapi'] = {};AWS.ApiGatewayManagementApi = Service.defineService('apigatewaymanagementapi', ['2018-11-29']);Object.defineProperty(apiLoader.services['apigatewaymanagementapi'], '2018-11-29', {  get: function get() {    var model = {      "metadata": {        "apiVersion": "2018-11-29",        "endpointPrefix": "execute-api",        "signingName": "execute-api",        "serviceFullName": "AmazonApiGatewayManagementApi",        "serviceId": "ApiGatewayManagementApi",        "protocol": "rest-json",        "jsonVersion": "1.1",        "uid": "apigatewaymanagementapi-2018-11-29",        "signatureVersion": "v4"      },      "operations": {        "PostToConnection": {          "http": {            "requestUri": "/@connections/{connectionId}",            "responseCode": 200          },          "input": {            "type": "structure",            "members": {              "Data": {                "type": "blob"              },              "ConnectionId": {                "location": "uri",                "locationName": "connectionId"              }            },            "required": [              "ConnectionId",              "Data"            ],            "payload": "Data"          }        }      },      "shapes": {}    }    model.paginators = {      "pagination": {}    }    return model;  },  enumerable: true,  configurable: true});
module.exports = AWS.ApiGatewayManagementApi;

I took the above code from this article. The functionality of this code is to automatically create the Callback URL for our API and send the POST request.

我从本文中获取了以上代码。 此代码的功能是自动为我们的API创建回调URL并发送POST请求。

Now that we have created the lambda function we can go ahead and create our custom route in API Gateway. In the New Route Key, add ‘OnMessage’ as a route and add the custom route. As configurations were done for other routes, add our lambda function to this custom route and deploy the API.

现在我们已经创建了lambda函数,我们可以继续在API Gateway中创建自定义路由。 在“新路由键”中,添加“ OnMessage”作为路由并添加自定义路由。 完成其他路由的配置后,将lambda函数添加到此自定义路由并部署API。

Now we have completed our WebSocket API and we can fully test the application. To test that sending messages works for multiple devices, we can open and connect using multiple terminals.

现在,我们已经完成了WebSocket API,并且可以完全测试该应用程序。 为了测试发送消息是否适用于多个设备,我们可以使用多个终端打开并连接。

After connecting, issue the following JSON to send messages:

连接后,发出以下JSON发送消息:

{"action" : "onMessage" , "message" : "Hello everyone"}

Here, the action is the custom route we defined and the message is the data that need to be sent to other devices.

在这里,操作是我们定义的自定义路由,消息是需要发送到其他设备的数据。

That is it for our simple chat application using AWS WebSocket API. We have not actually configured the $defalut route which is called on every occasion where there no route is found. I will leave the implementation of that route to you. Thank you and see you in another post. :)

就是使用AWS WebSocket API的简单聊天应用程序。 我们实际上并未配置$ defalut路由,该路由在每次找不到路由的情况下都会被调用。 我将把这条路线的实施留给您。 谢谢,再见。 :)

翻译自: https://www.freecodecamp.org/news/real-time-applications-using-websockets-with-aws-api-gateway-and-lambda-a5bb493e9452/

websockets

websockets_如何将WebSockets与AWS API Gateway和Lambda一起使用来构建实时应用程序相关推荐

  1. AWS API GATEWAY的使用

    AWS API GATEWAY 文章目录 1.Create Vpc endpoint 2.Target Groups与Load Balancer 2.1.Create target type为Inst ...

  2. AWS API gateway api CORS错误处理方法

    我们开发了一个 AWS lambda 函数,然后我们使用 AWS API gateway服务将它上线. 我们已经测试 API 并验证它是否按照我们的预期工作,看起来真的很棒. 现在我们准备好将 API ...

  3. aws api gateway 创建

    在这个章节中,你将创建一个无服务器API.无服务器API让你专注于你的应用,而不是花时间配置和管理服务器. 首先,你使用AWS Lambda控制台创建一个Lambda函数.接下来,你使用API网关控制 ...

  4. 使用 Learner Lab - 使用 S3 静态网页上传图片,搭配 API Gateway 与 Lambda

    使用 Learner Lab - 使用 S3 静态网页上传图片,搭配 API Gateway 与 Lambda AWS Academy Learner Lab 是提供一个帐号让学生可以自行使用 AWS ...

  5. aws api gateway 使用阿里云的域名访问

    创建apigateway 我创建的是Rest Api的网关 创建lambda函数 首先得创建一个lambda函数,代码我用的是golang 1.x.代码如下: package mainimport ( ...

  6. AWS API Gateway 绑定自己的域名

    由于中国区的AWS服务缺少或者功能不全,导致目前能找到的给API GateWay绑定域名的文档和资料都不够准确,因此在这记录一下中国区的操作步骤. 准备域名证书,需要以下材料 证书正文(一般名字是ce ...

  7. aws api gateway 设置WebSocket API集成请求

    设置一个集成请求包括以下内容. 选择一个路由密钥来集成到后端. 指定要调用的后端端点,如AWS服务或HTTP端点. 通过指定一个或多个请求模板,配置如何将路由请求数据(如有必要)转换为集成请求数据. ...

  8. AWS API Gateway与AWS Lambda代理集成构建REST API

    项目地址 https://github.com/JessicaWin/aws lambda分支为自动创建API Gateway REST API资源的部署方式 apigateway分支为自定义API ...

  9. aws api gateway 创建一个REST API作为Amazon S3代理

    你可能想把样本API导入为Amazon S3的代理,如样本API作为Amazon S3代理的OpenAPI定义所示.关于如何使用OpenAPI定义导入API的说明,请参阅使用OpenAPI配置REST ...

最新文章

  1. python爬取新闻后提炼_Python爬虫开发的3大难题,别上了贼船才发现,水有多深...
  2. synchronized的四种用法
  3. 微型计算机接口位于什么之间,io接口位于什么和什么之间
  4. 无边框窗体的移动(winform/wpf)
  5. Summary of GATT Profile Attribute Types
  6. boost::outcome模块outcome相关的测试程序
  7. FairyGUI1:FairyGUI 编辑器
  8. spark入门(1)
  9. 解决idea下tomcat乱码
  10. 固件工程师到底是干什么?
  11. Python全栈工程师系列学习之学习记录
  12. 立即寻址,直接寻址,间接寻址
  13. 圣经中真的藏有密码吗? 摘自台湾权威杂志《科学月刊》
  14. 决策树系列(二)——基于决策树算法实现泰坦尼克号生还预测
  15. 计算机黑屏启动超慢,电脑开机很慢然后黑屏连不上网怎么办(新手可学的4种简单处理方法)...
  16. ajax 轮询请求后台服务器
  17. android自动化测试辅助工具Weinre
  18. A Grain of Sand ——一砂一极乐
  19. 音量(DB)为什么都是负值
  20. 功能软件(一):以IDM对抗百度网盘!

热门文章

  1. android专栏目录
  2. 简单几步写一个laravel扩展包
  3. Java 内存查看与分析
  4. [转]CSS hack大全详解
  5. 查看CentOS的网络带宽出口
  6. 如何写一篇好的技术博客
  7. 解决vim没有颜色的办法
  8. {} 与 function() { } , 选用空对象{}来存放keyValue
  9. ant学习笔记之(ant执行命令的详细参数和Ant自带的系统属性)
  10. win7操作系统在哪显示隐藏文件夹