{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-05-09-serverless-websocket","result":{"data":{"currentBlog":{"id":"2ed40490-e6db-51f2-a0a0-8fa52c3488d7","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207418781-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-09T00:00:00.000Z","title":"Serverless 与 Websocket 的聊天工具","description":"传统业务实现 Websocket 并不难，然而函数计算基本上都是事件驱动，不支持长链接操作。如果将函数计算与 API 网关结合，是否可以有 Websocket 的实现方案呢？","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","Websocket"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":263,"sentences":43,"paragraphs":43},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-09-serverless-websocket.md","fields":{"slug":"/best-practice/2020-05-09-serverless-websocket/","keywords":["java","python","serverless","函数计算","云函数","secret","网关","item","客户端","Conf","bucket","retmsg","os"]},"html":"<p>传统业务实现 Websocket 并不难，然而函数计算基本上都是事件驱动，不支持长链接操作。如果将函数计算与 API 网关结合，是否可以有 Websocket 的实现方案呢？</p>\n<h2 id=\"api-网关触发器实现-websocket\"><a href=\"#api-%E7%BD%91%E5%85%B3%E8%A7%A6%E5%8F%91%E5%99%A8%E5%AE%9E%E7%8E%B0-websocket\" aria-label=\"api 网关触发器实现 websocket permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>API 网关触发器实现 Websocket</h2>\n<p>WebSocket 协议是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工 (full-duplex) 通信，即允许服务器主动发送信息给客户端。WebSocket 在服务端有数据推送需求时，可以主动发送数据至客户端。而原有 HTTP 协议的服务端对于需推送的数据，仅能通过轮询或 long poll 的方式来让客户端获得。</p>\n<p>由于云函数是无状态且以触发式运行，即在有事件到来时才会被触发。因此，为了实现 WebSocket，云函数 SCF 与 API 网关相结合，通过 API 网关承接及保持与客户端的连接。您可以认为云函数与 API 网关一起实现了服务端。当客户端有消息发出时，会先传递给 API 网关，再由 API 网关触发云函数执行。当服务端云函数要向客户端发送消息时，会先由云函数将消息 POST 到 API 网关的反向推送链接，再由 API 网关向客户端完成消息的推送。</p>\n<p>具体的实现架构如下：</p>\n<p><img src=\"https://img.serverlesscloud.cn/tmp/2-8-2.png\" alt=\"实现架构\"></p>\n<p>对于 WebSocket 的整个生命周期，主要由以下几个事件组成：</p>\n<ul>\n<li>连接建立：客户端向服务端请求建立连接并完成连接建立；</li>\n<li>数据上行：客户端通过已经建立的连接向服务端发送数据；</li>\n<li>数据下行：服务端通过已经建立的连接向客户端发送数据；</li>\n<li>客户端断开：客户端要求断开已经建立的连接；</li>\n<li>服务端断开：服务端要求断开已经建立的连接。</li>\n</ul>\n<p>对于 WebSocket 整个生命周期的事件，云函数和 API 网关的处理过程如下：</p>\n<ul>\n<li>连接建立：客户端与 API 网关建立 WebSocket 连接，API 网关将连接建立事件发送给 SCF；</li>\n<li>数据上行：客户端通过 WebSocket 发送数据，API 网关将数据转发送给 SCF；</li>\n<li>数据下行：SCF 通过向 API 网关指定的推送地址发送请求，API 网关收到后会将数据通过 WebSocket 发送给客户端；</li>\n<li>客户端断开：客户端请求断开连接，API 网关将连接断开事件发送给 SCF；</li>\n<li>服务端断开：SCF 通过向 API 网关指定的推送地址发送断开请求，API 网关收到后断开 WebSocket 连接。</li>\n</ul>\n<p>因此，云函数与 API 网关之间的交互，需要由 3 类云函数来承载：</p>\n<ul>\n<li>注册函数：在客户端发起和 API 网关之间建立 WebSocket 连接时触发该函数，通知 SCF WebSocket 连接的 secConnectionID。通常会在该函数记录 secConnectionID 到持久存储中，用于后续数据的反向推送；</li>\n<li>清理函数：在客户端主动发起 WebSocket 连接中断请求时触发该函数，通知 SCF 准备断开连接的 secConnectionID。通常会在该函数清理持久存储中记录的该 secConnectionID；</li>\n<li>传输函数：在客户端通过 WebSocket 连接发送数据时触发该函数，告知 SCF 连接的 secConnectionID 以及发送的数据。通常会在该函数处理业务数据。例如，是否将数据推送给持久存储中的其他 secConnectionID。</li>\n</ul>\n<h2 id=\"websocket-功能实现\"><a href=\"#websocket-%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0\" aria-label=\"websocket 功能实现 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Websocket 功能实现</h2>\n<p>根据腾讯云官网提供的该功能的整体架构图：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/2-8-3.png\" alt=\"整体架构图\"></p>\n<p>这里我们可以使用对象存储 COS 作为持久化的方案，当用户建立链接存储 <code class=\"language-text\">ConnectionId</code> 到 COS 中，当用户断开连接删除该链接 ID。</p>\n<p>其中注册函数：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"56603066781185050000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# -*- coding: utf8 -*-\nimport os\nfrom qcloud_cos_v5 import CosConfig\nfrom qcloud_cos_v5 import CosS3Client\n\nbucket = os.environ.get('bucket')\nregion = os.environ.get('region')\nsecret_id = os.environ.get('secret_id')\nsecret_key = os.environ.get('secret_key')\ncosClient = CosS3Client(CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key))\n\n\ndef main_handler(event, context):\n    print(&quot;event is %s&quot; % event)\n\n    connectionID = event['websocket']['secConnectionID']\n\n    retmsg = {}\n    retmsg['errNo'] = 0\n    retmsg['errMsg'] = &quot;ok&quot;\n    retmsg['websocket'] = {\n        &quot;action&quot;: &quot;connecting&quot;,\n        &quot;secConnectionID&quot;: connectionID\n    }\n\n    cosClient.put_object(\n        Bucket=bucket,\n        Body='websocket'.encode(&quot;utf-8&quot;),\n        Key=str(connectionID),\n        EnableMD5=False\n    )\n\n    return retmsg`, `56603066781185050000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># -*- coding: utf8 -*-</span>\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosConfig\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosS3Client\n\nbucket <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'bucket'</span><span class=\"token punctuation\">)</span>\nregion <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'region'</span><span class=\"token punctuation\">)</span>\nsecret_id <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_id'</span><span class=\"token punctuation\">)</span>\nsecret_key <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_key'</span><span class=\"token punctuation\">)</span>\ncosClient <span class=\"token operator\">=</span> CosS3Client<span class=\"token punctuation\">(</span>CosConfig<span class=\"token punctuation\">(</span>Region<span class=\"token operator\">=</span>region<span class=\"token punctuation\">,</span> SecretId<span class=\"token operator\">=</span>secret_id<span class=\"token punctuation\">,</span> SecretKey<span class=\"token operator\">=</span>secret_key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"event is %s\"</span> <span class=\"token operator\">%</span> event<span class=\"token punctuation\">)</span>\n\n    connectionID <span class=\"token operator\">=</span> event<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'secConnectionID'</span><span class=\"token punctuation\">]</span>\n\n    retmsg <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'errNo'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'errMsg'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"ok\"</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"action\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"connecting\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"secConnectionID\"</span><span class=\"token punctuation\">:</span> connectionID\n    <span class=\"token punctuation\">}</span>\n\n    cosClient<span class=\"token punctuation\">.</span>put_object<span class=\"token punctuation\">(</span>\n        Bucket<span class=\"token operator\">=</span>bucket<span class=\"token punctuation\">,</span>\n        Body<span class=\"token operator\">=</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">.</span>encode<span class=\"token punctuation\">(</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        Key<span class=\"token operator\">=</span><span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>connectionID<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        EnableMD5<span class=\"token operator\">=</span><span class=\"token boolean\">False</span>\n    <span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">return</span> retmsg</code></pre></div>\n<p>传输函数：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"14035926315106394000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# -*- coding: utf8 -*-\nimport os\nimport json\nimport requests\nfrom qcloud_cos_v5 import CosConfig\nfrom qcloud_cos_v5 import CosS3Client\n\nbucket = os.environ.get('bucket')\nregion = os.environ.get('region')\nsecret_id = os.environ.get('secret_id')\nsecret_key = os.environ.get('secret_key')\ncosClient = CosS3Client(CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key))\n\nsendbackHost = os.environ.get(&quot;url&quot;)\n\n\ndef Get_ConnectionID_List():\n    response = cosClient.list_objects(\n        Bucket=bucket,\n    )\n    return [eve['Key'] for eve in response['Contents']]\n\n\ndef send(connectionID, data):\n    retmsg = {}\n    retmsg['websocket'] = {}\n    retmsg['websocket']['action'] = &quot;data send&quot;\n    retmsg['websocket']['secConnectionID'] = connectionID\n    retmsg['websocket']['dataType'] = 'text'\n    retmsg['websocket']['data'] = data\n    requests.post(sendbackHost, json=retmsg)\n\n\ndef main_handler(event, context):\n    print(&quot;event is %s&quot; % event)\n\n    connectionID_List = Get_ConnectionID_List()\n    connectionID = event['websocket']['secConnectionID']\n    count = len(connectionID_List)\n    data = event['websocket']['data'] + &quot;(===Online people:&quot; + str(count) + &quot;===)&quot;\n    for ID in connectionID_List:\n        if ID != connectionID:\n            send(ID, data)\n\n    return &quot;send success&quot;`, `14035926315106394000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># -*- coding: utf8 -*-</span>\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">import</span> json\n<span class=\"token keyword\">import</span> requests\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosConfig\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosS3Client\n\nbucket <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'bucket'</span><span class=\"token punctuation\">)</span>\nregion <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'region'</span><span class=\"token punctuation\">)</span>\nsecret_id <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_id'</span><span class=\"token punctuation\">)</span>\nsecret_key <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_key'</span><span class=\"token punctuation\">)</span>\ncosClient <span class=\"token operator\">=</span> CosS3Client<span class=\"token punctuation\">(</span>CosConfig<span class=\"token punctuation\">(</span>Region<span class=\"token operator\">=</span>region<span class=\"token punctuation\">,</span> SecretId<span class=\"token operator\">=</span>secret_id<span class=\"token punctuation\">,</span> SecretKey<span class=\"token operator\">=</span>secret_key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\nsendbackHost <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"url\"</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">Get_ConnectionID_List</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    response <span class=\"token operator\">=</span> cosClient<span class=\"token punctuation\">.</span>list_objects<span class=\"token punctuation\">(</span>\n        Bucket<span class=\"token operator\">=</span>bucket<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span>eve<span class=\"token punctuation\">[</span><span class=\"token string\">'Key'</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">for</span> eve <span class=\"token keyword\">in</span> response<span class=\"token punctuation\">[</span><span class=\"token string\">'Contents'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">]</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">send</span><span class=\"token punctuation\">(</span>connectionID<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    retmsg <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'action'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"data send\"</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'secConnectionID'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> connectionID\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'dataType'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">'text'</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'data'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> data\n    requests<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">(</span>sendbackHost<span class=\"token punctuation\">,</span> json<span class=\"token operator\">=</span>retmsg<span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"event is %s\"</span> <span class=\"token operator\">%</span> event<span class=\"token punctuation\">)</span>\n\n    connectionID_List <span class=\"token operator\">=</span> Get_ConnectionID_List<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    connectionID <span class=\"token operator\">=</span> event<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'secConnectionID'</span><span class=\"token punctuation\">]</span>\n    count <span class=\"token operator\">=</span> <span class=\"token builtin\">len</span><span class=\"token punctuation\">(</span>connectionID_List<span class=\"token punctuation\">)</span>\n    data <span class=\"token operator\">=</span> event<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'data'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"(===Online people:\"</span> <span class=\"token operator\">+</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>count<span class=\"token punctuation\">)</span> <span class=\"token operator\">+</span> <span class=\"token string\">\"===)\"</span>\n    <span class=\"token keyword\">for</span> ID <span class=\"token keyword\">in</span> connectionID_List<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">if</span> ID <span class=\"token operator\">!=</span> connectionID<span class=\"token punctuation\">:</span>\n            send<span class=\"token punctuation\">(</span>ID<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token string\">\"send success\"</span></code></pre></div>\n<p>清理函数：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"76983917590300570000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# -*- coding: utf8 -*-\nimport os\nimport requests\nfrom qcloud_cos_v5 import CosConfig\nfrom qcloud_cos_v5 import CosS3Client\n\nbucket = os.environ.get('bucket')\nregion = os.environ.get('region')\nsecret_id = os.environ.get('secret_id')\nsecret_key = os.environ.get('secret_key')\ncosClient = CosS3Client(CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key))\n\nsendbackHost = os.environ.get(&quot;url&quot;)\n\n\ndef main_handler(event, context):\n    print(&quot;event is %s&quot; % event)\n\n    connectionID = event['websocket']['secConnectionID']\n\n    retmsg = {}\n    retmsg['websocket'] = {}\n    retmsg['websocket']['action'] = &quot;closing&quot;\n    retmsg['websocket']['secConnectionID'] = connectionID\n    requests.post(sendbackHost, json=retmsg)\n\n    cosClient.delete_object(\n        Bucket=bucket,\n        Key=str(connectionID),\n    )\n\n    return event`, `76983917590300570000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token comment\"># -*- coding: utf8 -*-</span>\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">import</span> requests\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosConfig\n<span class=\"token keyword\">from</span> qcloud_cos_v5 <span class=\"token keyword\">import</span> CosS3Client\n\nbucket <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'bucket'</span><span class=\"token punctuation\">)</span>\nregion <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'region'</span><span class=\"token punctuation\">)</span>\nsecret_id <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_id'</span><span class=\"token punctuation\">)</span>\nsecret_key <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'secret_key'</span><span class=\"token punctuation\">)</span>\ncosClient <span class=\"token operator\">=</span> CosS3Client<span class=\"token punctuation\">(</span>CosConfig<span class=\"token punctuation\">(</span>Region<span class=\"token operator\">=</span>region<span class=\"token punctuation\">,</span> SecretId<span class=\"token operator\">=</span>secret_id<span class=\"token punctuation\">,</span> SecretKey<span class=\"token operator\">=</span>secret_key<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\nsendbackHost <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">\"url\"</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"event is %s\"</span> <span class=\"token operator\">%</span> event<span class=\"token punctuation\">)</span>\n\n    connectionID <span class=\"token operator\">=</span> event<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'secConnectionID'</span><span class=\"token punctuation\">]</span>\n\n    retmsg <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'action'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"closing\"</span>\n    retmsg<span class=\"token punctuation\">[</span><span class=\"token string\">'websocket'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'secConnectionID'</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> connectionID\n    requests<span class=\"token punctuation\">.</span>post<span class=\"token punctuation\">(</span>sendbackHost<span class=\"token punctuation\">,</span> json<span class=\"token operator\">=</span>retmsg<span class=\"token punctuation\">)</span>\n\n    cosClient<span class=\"token punctuation\">.</span>delete_object<span class=\"token punctuation\">(</span>\n        Bucket<span class=\"token operator\">=</span>bucket<span class=\"token punctuation\">,</span>\n        Key<span class=\"token operator\">=</span><span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>connectionID<span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">return</span> event</code></pre></div>\n<p>Yaml 文件如下：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"9010118745810103000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`Conf:\n  component: &quot;serverless-global&quot;\n  inputs:\n    region: ap-guangzhou\n    bucket: chat-cos-1256773370\n    secret_id:\n    secret_key:\n\nmyBucket:\n  component: '@serverless/tencent-cos'\n  inputs:\n    bucket: \\${Conf.bucket}\n    region: \\${Conf.region}\n\nrestApi:\n  component: '@serverless/tencent-apigateway'\n  inputs:\n    region: \\${Conf.region}\n    protocols:\n      - http\n      - https\n    serviceName: ChatDemo\n    environment: release\n    endpoints:\n      - path: /\n        method: GET\n        protocol: WEBSOCKET\n        serviceTimeout: 800\n        function:\n          transportFunctionName: ChatTrans\n          registerFunctionName: ChatReg\n          cleanupFunctionName: ChatClean\n\n\nChatReg:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: ChatReg\n    codeUri: ./code\n    handler: reg.main_handler\n    runtime: Python3.6\n    region:  \\${Conf.region}\n    environment:\n      variables:\n        region: \\${Conf.region}\n        bucket: \\${Conf.bucket}\n        secret_id: \\${Conf.secret_id}\n        secret_key: \\${Conf.secret_key}\n        url: http://set-gwm9thyc.cb-guangzhou.apigateway.tencentyun.com/api-etj7lhtw\n\nChatTrans:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: ChatTrans\n    codeUri: ./code\n    handler: trans.main_handler\n    runtime: Python3.6\n    region:  \\${Conf.region}\n    environment:\n      variables:\n        region: \\${Conf.region}\n        bucket: \\${Conf.bucket}\n        secret_id: \\${Conf.secret_id}\n        secret_key: \\${Conf.secret_key}\n        url: http://set-gwm9thyc.cb-guangzhou.apigateway.tencentyun.com/api-etj7lhtw\n\nChatClean:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: ChatClean\n    codeUri: ./code\n    handler: clean.main_handler\n    runtime: Python3.6\n    region:  \\${Conf.region}\n    environment:\n      variables:\n        region: \\${Conf.region}\n        bucket: \\${Conf.bucket}\n        secret_id: \\${Conf.secret_id}\n        secret_key: \\${Conf.secret_key}\n        url: http://set-gwm9thyc.cb-guangzhou.apigateway.tencentyun.com/api-etj7lhtw`, `9010118745810103000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token key atrule\">Conf</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"serverless-global\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> ap<span class=\"token punctuation\">-</span>guangzhou\n    <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> chat<span class=\"token punctuation\">-</span>cos<span class=\"token punctuation\">-</span><span class=\"token number\">1256773370</span>\n    <span class=\"token key atrule\">secret_id</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">secret_key</span><span class=\"token punctuation\">:</span>\n\n<span class=\"token key atrule\">myBucket</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'@serverless/tencent-cos'</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.bucket<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n\n<span class=\"token key atrule\">restApi</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'@serverless/tencent-apigateway'</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">protocols</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> http\n      <span class=\"token punctuation\">-</span> https\n    <span class=\"token key atrule\">serviceName</span><span class=\"token punctuation\">:</span> ChatDemo\n    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span> release\n    <span class=\"token key atrule\">endpoints</span><span class=\"token punctuation\">:</span>\n      <span class=\"token punctuation\">-</span> <span class=\"token key atrule\">path</span><span class=\"token punctuation\">:</span> /\n        <span class=\"token key atrule\">method</span><span class=\"token punctuation\">:</span> GET\n        <span class=\"token key atrule\">protocol</span><span class=\"token punctuation\">:</span> WEBSOCKET\n        <span class=\"token key atrule\">serviceTimeout</span><span class=\"token punctuation\">:</span> <span class=\"token number\">800</span>\n        <span class=\"token key atrule\">function</span><span class=\"token punctuation\">:</span>\n          <span class=\"token key atrule\">transportFunctionName</span><span class=\"token punctuation\">:</span> ChatTrans\n          <span class=\"token key atrule\">registerFunctionName</span><span class=\"token punctuation\">:</span> ChatReg\n          <span class=\"token key atrule\">cleanupFunctionName</span><span class=\"token punctuation\">:</span> ChatClean\n\n\n<span class=\"token key atrule\">ChatReg</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-scf\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> ChatReg\n    <span class=\"token key atrule\">codeUri</span><span class=\"token punctuation\">:</span> ./code\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> reg.main_handler\n    <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Python3.6\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span>  $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.bucket<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_id</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_id<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_key</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_key<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">url</span><span class=\"token punctuation\">:</span> http<span class=\"token punctuation\">:</span>//set<span class=\"token punctuation\">-</span>gwm9thyc.cb<span class=\"token punctuation\">-</span>guangzhou.apigateway.tencentyun.com/api<span class=\"token punctuation\">-</span>etj7lhtw\n\n<span class=\"token key atrule\">ChatTrans</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-scf\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> ChatTrans\n    <span class=\"token key atrule\">codeUri</span><span class=\"token punctuation\">:</span> ./code\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> trans.main_handler\n    <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Python3.6\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span>  $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.bucket<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_id</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_id<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_key</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_key<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">url</span><span class=\"token punctuation\">:</span> http<span class=\"token punctuation\">:</span>//set<span class=\"token punctuation\">-</span>gwm9thyc.cb<span class=\"token punctuation\">-</span>guangzhou.apigateway.tencentyun.com/api<span class=\"token punctuation\">-</span>etj7lhtw\n\n<span class=\"token key atrule\">ChatClean</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">component</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"@serverless/tencent-scf\"</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">name</span><span class=\"token punctuation\">:</span> ChatClean\n    <span class=\"token key atrule\">codeUri</span><span class=\"token punctuation\">:</span> ./code\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> clean.main_handler\n    <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Python3.6\n    <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span>  $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n    <span class=\"token key atrule\">environment</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">variables</span><span class=\"token punctuation\">:</span>\n        <span class=\"token key atrule\">region</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.region<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">bucket</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.bucket<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_id</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_id<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">secret_key</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.secret_key<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">url</span><span class=\"token punctuation\">:</span> http<span class=\"token punctuation\">:</span>//set<span class=\"token punctuation\">-</span>gwm9thyc.cb<span class=\"token punctuation\">-</span>guangzhou.apigateway.tencentyun.com/api<span class=\"token punctuation\">-</span>etj7lhtw</code></pre></div>\n<p>注意，这里需要先部署 API 网关。当部署完成，获得回推地址，将回推地址以 url 的形式写入到对应函数的环境变量中：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-8-4.png\"></p>\n<p>理论上应该是可以通过 <code class=\"language-text\">${restApi.url[0].internalDomain}</code> 自动获得到 url 的，但是我并没有成功获得到这个 url，只能先部署 API 网关，获得到这个地址之后，再重新部署。</p>\n<p>部署完成之后，我们可以编写 HTML 代码，实现可视化的 Websocket Client，其核心的 JavaScript 代码为：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"27981019698291433000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`window.onload = function () {\n    var conn;\n    var msg = document.getElementById(&quot;msg&quot;);\n    var log = document.getElementById(&quot;log&quot;);\n\n    function appendLog(item) {\n        var doScroll = log.scrollTop === log.scrollHeight - log.clientHeight;\n        log.appendChild(item);\n        if (doScroll) {\n            log.scrollTop = log.scrollHeight - log.clientHeight;\n        }\n    }\n\n    document.getElementById(&quot;form&quot;).onsubmit = function () {\n        if (!conn) {\n            return false;\n        }\n        if (!msg.value) {\n            return false;\n        }\n        conn.send(msg.value);\n        //msg.value = &quot;&quot;;\n\n\t\tvar item = document.createElement(&quot;div&quot;);\n\t\titem.innerText = &quot;发送↑:&quot;;\n\t\tappendLog(item);\n\n\t\tvar item = document.createElement(&quot;div&quot;);\n\t\titem.innerText = msg.value;\n\t\tappendLog(item);\n\n        return false;\n    };\n\n    if (window[&quot;WebSocket&quot;]) {\n        //替换为websocket连接地址\n        conn = new WebSocket(&quot;ws://service-01era6ni-1256773370.gz.apigw.tencentcs.com/release/&quot;);\n        conn.onclose = function (evt) {\n            var item = document.createElement(&quot;div&quot;);\n            item.innerHTML = &quot;<b>Connection closed.</b>&quot;;\n            appendLog(item);\n        };\n        conn.onmessage = function (evt) {\n\t\t\tvar item = document.createElement(&quot;div&quot;);\n\t\t\titem.innerText = &quot;接收↓:&quot;;\n\t\t\tappendLog(item);\n\n            var messages = evt.data.split('\\n');\n            for (var i = 0; i < messages.length; i++) {\n                var item = document.createElement(&quot;div&quot;);\n                item.innerText = messages[i];\n                appendLog(item);\n            }\n        };\n    } else {\n        var item = document.createElement(&quot;div&quot;);\n        item.innerHTML = &quot;<b>Your browser does not support WebSockets.</b>&quot;;\n        appendLog(item);\n    }\n};`, `27981019698291433000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\">window<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onload</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">var</span> conn<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">var</span> msg <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"msg\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">var</span> log <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"log\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">function</span> <span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">var</span> doScroll <span class=\"token operator\">=</span> log<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">===</span> log<span class=\"token punctuation\">.</span>scrollHeight <span class=\"token operator\">-</span> log<span class=\"token punctuation\">.</span>clientHeight<span class=\"token punctuation\">;</span>\n        log<span class=\"token punctuation\">.</span><span class=\"token function\">appendChild</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>doScroll<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            log<span class=\"token punctuation\">.</span>scrollTop <span class=\"token operator\">=</span> log<span class=\"token punctuation\">.</span>scrollHeight <span class=\"token operator\">-</span> log<span class=\"token punctuation\">.</span>clientHeight<span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n\n    document<span class=\"token punctuation\">.</span><span class=\"token function\">getElementById</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"form\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onsubmit</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>conn<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>msg<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        conn<span class=\"token punctuation\">.</span><span class=\"token function\">send</span><span class=\"token punctuation\">(</span>msg<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token comment\">//msg.value = \"\";</span>\n\n\t\t<span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> <span class=\"token string\">\"发送↑:\"</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n\t\t<span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> msg<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">;</span>\n\t\t<span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">[</span><span class=\"token string\">\"WebSocket\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">//替换为websocket连接地址</span>\n        conn <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">WebSocket</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"ws://service-01era6ni-1256773370.gz.apigw.tencentcs.com/release/\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        conn<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onclose</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">evt</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            item<span class=\"token punctuation\">.</span>innerHTML <span class=\"token operator\">=</span> <span class=\"token string\">\"&lt;b>Connection closed.&lt;/b>\"</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n        conn<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">onmessage</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">evt</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t<span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\titem<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> <span class=\"token string\">\"接收↓:\"</span><span class=\"token punctuation\">;</span>\n\t\t\t<span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n            <span class=\"token keyword\">var</span> messages <span class=\"token operator\">=</span> evt<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span><span class=\"token function\">split</span><span class=\"token punctuation\">(</span><span class=\"token string\">'\\n'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">var</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> messages<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                item<span class=\"token punctuation\">.</span>innerText <span class=\"token operator\">=</span> messages<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n                <span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">var</span> item <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"div\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        item<span class=\"token punctuation\">.</span>innerHTML <span class=\"token operator\">=</span> <span class=\"token string\">\"&lt;b>Your browser does not support WebSockets.&lt;/b>\"</span><span class=\"token punctuation\">;</span>\n        <span class=\"token function\">appendLog</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>完成之后，我们打开两个页面，进行测试：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-8-5.png\"></p>\n<h2 id=\"总结\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>通过云函数 + API 网关进行 Websocket 的实践，绝对不仅仅是一个聊天工具这么简单，它可以用在很多方面，例如通过 Websocket 进行实时日志系统的制作等。</p>\n<p>单独的函数计算，仅仅是一个计算平台，只有和周边的 BaaS 结合，才能展示出 Serverless 架构的价值和真正的能力。这也是为什么很多人说 Serverless=FaaS+BaaS 的一个原因。</p>\n<p>期待更多小伙伴，可以通过 Serverless 架构，创造出更多有趣的应用。</p>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<blockquote>\n<p><strong>传送门：</strong></p>\n<ul>\n<li>GitHub: <a href=\"https://github.com/serverless/serverless/blob/master/README_CN.md\">github.com/serverless</a></li>\n<li>官网：<a href=\"https://serverless.com/\">serverless.com</a></li>\n</ul>\n</blockquote>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2020-05-09-serverless-websocket/#api-%E7%BD%91%E5%85%B3%E8%A7%A6%E5%8F%91%E5%99%A8%E5%AE%9E%E7%8E%B0-websocket\">API 网关触发器实现 Websocket</a></li>\n<li><a href=\"/best-practice/2020-05-09-serverless-websocket/#websocket-%E5%8A%9F%E8%83%BD%E5%AE%9E%E7%8E%B0\">Websocket 功能实现</a></li>\n<li><a href=\"/best-practice/2020-05-09-serverless-websocket/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"e1770fad-8a66-5619-88f6-ef5e50448400","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207417699-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-10T00:00:00.000Z","title":"从企业微信机器人到小爱同学，用 Serverless 实现生活智能化！","description":"通过定时触发器，可以非常简单快速地建立一个企业微信机器人。我们可以用它来实现喝水、吃饭提醒等小功能，还能实现定时推送新闻、天气，甚至是监控告警的小功能","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","企业微信"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":null},"wordCount":{"words":219,"sentences":54,"paragraphs":54},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-10-enterprise-wechat.md","fields":{"slug":"/best-practice/2020-05-10-enterprise-wechat/","keywords":["go","python","serverless","云函数","request","urllib","attr","json"]}},"nextBlog":{"id":"249242aa-c81b-5ff8-9553-90e8792af73e","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207417923-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-05-08T00:00:00.000Z","title":"云函数 SCF 与对象存储实现 WordCount","description":"本文将通过 MapReduce 模型实现一个简单的 WordCount 算法，区别于传统使用 Hadoop 等大数据框架，本文使用的是对象存储 COS 与云函数 SCF 的结合","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Serverless","WordCount"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":181,"sentences":28,"paragraphs":28},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-05-08-wordcount.md","fields":{"slug":"/best-practice/2020-05-08-wordcount/","keywords":["python","serverless","云函数","file","cos","bucket","client","event"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"2ed40490-e6db-51f2-a0a0-8fa52c3488d7","previousBlogId":"e1770fad-8a66-5619-88f6-ef5e50448400","nextBlogId":"249242aa-c81b-5ff8-9553-90e8792af73e"}}}