{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-04-19-applets","result":{"data":{"currentBlog":{"id":"99725ecb-905b-5852-a6c7-80e83df8d7f9","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589274868260-071529vaxztt.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-19T00:00:00.000Z","title":"基于 Serverless Framework 的人工智能小程序开发","description":"本示例将会通过微信小程序，在 Serverless 架构上，实现一款基于人工智能的相册小工具！","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["小程序","人工智能"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":541,"sentences":90,"paragraphs":90},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-19-applets.md","fields":{"slug":"/best-practice/2020-04-19-applets/","keywords":["go","python","serverless","website","云函数","mysql","函数","功能","remark","Components"]},"html":"<p>在日常生活中，我们经常会遇到搜索照片的情况，尤其是对寻找过去很久的图片，记忆中仅剩下零散的记忆的时候，我们检索照片的方法通常是定位到大致的时间，然后一张一张的去查看，但是这种做法效率低下，还经常会漏掉我们的目标图片，所以这个时候，就迫切需要一款可以搜索图片的软件，即我们可以通过简单的文字描述，实现图片的快速检索。</p>\n<p>近几年微信小程序的发展速度飞快，从 2017 年年初，张小龙在 2017 微信公开课 Pro 上发布的小程序正式上线到目前为止，小程序已经覆盖了超过 200 个细分行业，服务超过 1000 亿人次用户，年交易增长超过 600%，创造超过 5000 亿的商业价值。而小程序蓬勃发展的背后，是一群优秀的小程序开发者的不断贡献。</p>\n<p>本实例将会通过微信小程序，在 Serverless 架构上，实现一款基于人工智能的相册小工具，该款小工具可以在保证基础相册功能（新建相册、删除相册、上传图片、查看图片、删除图片）的基础上，增加搜索功能，即用户上传图片之后，基于 Image Caption 技术，自动对图片进行描述，实现 Image to Text 的过程，当用户进行搜索时，通过文本间的相似度，返回给用户最贴近的图片。</p>\n<h2 id=\"基础设计\"><a href=\"#%E5%9F%BA%E7%A1%80%E8%AE%BE%E8%AE%A1\" 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><img src=\"https://img.serverlesscloud.cn/202058/3-6-1.png\"></p>\n<p>该项目设计主要拥有登录功能、相册新建、图片上传以及相关预览功能，以及搜索功能，整体如图所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-2.png\"></p>\n<p>其中注册功能的主要作用是，通过获取用户的唯一Id（微信中的OpenId），来讲用户信息存储到数据库中，之后的所有操作，都需要根据该 ID 作为区分。相册功能主要包括相册添加、修改、删除以及查看等功能。图片功能包括图片上传功能、删除功能、查看功能。搜索功能主要是可以查看指定标签对应的图片列表，以及指定搜索内容对应的列表。当然这四个主要功能和模块是和前端关系紧密的部分，除此之外还有后端异步操作的两个模块，分别是图像压缩功能以及图像描述功能。</p>\n<h4 id=\"注册功能：\"><a href=\"#%E6%B3%A8%E5%86%8C%E5%8A%9F%E8%83%BD%EF%BC%9A\" 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>注册功能：</h4>\n<p>注册功能主要是用户点击注册账号之后，执行的动作。该动作需要注意，用户点击注册账号注册的时候要先判断用户是否已经注册过，如果已经注册过则默认登陆，否则进行注册并登陆。当用户不想注册时，可以点击体验程序，可以对程序大部分页面进行预览。但是不能实现有关数据库的增删改查等功能。登录功能页面如图所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-3.png\"></p>\n<h4 id=\"相册功能：\"><a href=\"#%E7%9B%B8%E5%86%8C%E5%8A%9F%E8%83%BD%EF%BC%9A\" 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>相册功能：</h4>\n<p>当用户注册登录之后，可以在相册管理页面进行相册相关的管理，包括编辑功能，删除功能以及新建功能，此处在进行添加和修改的时候，需要注意相册名称是否已经存在；在进行删除相册，修改相册等操作时要判断用户是否有操作该相册的权限等，如图所示，是相册功能相关原型图。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-4.png\"></p>\n<h4 id=\"图片功能：\"><a href=\"#%E5%9B%BE%E7%89%87%E5%8A%9F%E8%83%BD%EF%BC%9A\" 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>图片功能：</h4>\n<p>图片功能主要包括图片列表以及图片获取、图片删除以及图片上传功能，在图片获取与删除的过程中，要对用户是否有该项操作的权限进行判断，图片上传时也要判断用户是否有上传到指定相册的权限。图片功能相关原型图如所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-5.png\"></p>\n<p>图片功能部分除了用户侧可见的功能，还有定时任务，当用户上传图片之后，系统会在后台异步进行图像压缩以及图像的描述，关键词提取等。整体流程如图所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-6.png\"></p>\n<h4 id=\"搜索功能：\"><a href=\"#%E6%90%9C%E7%B4%A2%E5%8A%9F%E8%83%BD%EF%BC%9A\" 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>搜索功能：</h4>\n<p>搜索功能指的是通过关键词或者使用者的描述，可以获得到目标数据的过程，这一功能原型图如图所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-7.png\"></p>\n<p>这一部分的难点和重点在于通过用户的描述，搜索到目标数据的过程。这个过程的基本流程如图所示。</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-8.png\"></p>\n<h2 id=\"项目开发\"><a href=\"#%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91\" 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<h3 id=\"初步了解-serverless-cli\"><a href=\"#%E5%88%9D%E6%AD%A5%E4%BA%86%E8%A7%A3-serverless-cli\" aria-label=\"初步了解 serverless cli 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>初步了解 Serverless ClI</h3>\n<p>Serverless 架构可以说是目前非常火热的项目，其凭借着按量付费、低成本运维、高效率开发等众多优点于一身，帮助我们的项目快速开发，快速迭代。而 Serverless Framework 则是一个非常高效的工具，其兼容了 AWS，Google Cloud 以及腾讯云等多家厂商的Serverless 架构，为开发者提供一个多云的开发者工具，目前以腾讯云为例，其拥有 Plugin 和 Components 两个部分。</p>\n<p>这两个部分可以说是个有千秋，具体的大家可以官方说明，或者自己体验一下。我这里我只说几个我觉得很头疼的问题。</p>\n<ul>\n<li>Plugin部署到线上的函数，会自动变更名字，例如我的函数是myFunction，我的服务和阶段是myService-Dev，那么函数部署到线上就是myService-Dev-myFunction，这样的函数名，很可能会让我的函数间调用等部分产生很多不可控因素。例如我现在的环境是Dev，我函数间调用就要写函数名是myService-Dev-myFunction，如果是我的环境是Test，此时就要写myService-Test-myFunction，我始终觉得，我更改环境应该只需要更改配置，而不是更深入的代码逻辑。所以我对Plugin的这个换名字问题很烦躁；</li>\n<li>Plugin也是有优势的，例如他有Invoke、Remove以及部署单个函数的功能，同时Plugin也有全局变量，我觉得这个更像一个开发者工具，我可以开发、部署、调用、查看一些信息、指标以及删除回滚等操作，都可以通过Plugin完成，这点很给力，我喜欢；</li>\n<li>Components可以看作是一个组件集，这里面包括了很多的Components，可以有基础的Components，例如cos、scf、apigateway等，也有一些拓展的Components，例如在cos上拓展出来的website，可以直接部署静态网站等，还有一些框架级的，例如Koa，Express，这些Components说实话，真的蛮方便的，腾讯官方也是有他们的最佳实践；</li>\n<li>Components除了刚才所说的支持的产品多，可以部署框架之外，对我来说，最大吸引力在于这个东西，部署到线上的函数名字就是我指定的名字，不会出现额外的东西，这个我非常看重；</li>\n<li>Components相对Plugin在功能上略显单薄，除了部署和删除，再没有其他，例如Plugin的Invoke，Rollback等等一切都没有，同时，我们如果有多个东西要部署，写到了一个Components的yaml上，那么我们每次部署都要部署所有的，如果我们认为，我们只修改了一个函数，并且不想重新部署其他函数从而注释掉其他函数，那么很抱歉告诉你，不行！他会看到你只有一个函数，并且帮你把你注释掉的函数在线上删除；</li>\n<li>Components更多的定义是组件，所以每个组件就是一个东西，所以在Components上面，是没有全局变量这一说法，这点我觉得很坑。</li>\n</ul>\n<p>综上所述的几点，就是在除了官方文档的描述之外，我对Plugin和Components的对比，感情真的可谓是错综复杂，也很期待产品策略可以将二者合并，或者功能对齐，否则单用Plugin，功能上是很全面了，但是产品支持不全面，名字变化我真的不能忍（可能很多人都不能忍），单用Components，没有全局变量，没有更多功能，可谓是产品广度变了，便利增加了，但是功能太淡薄了，我对二者的感情，又恨又爱。</p>\n<p>经过了长久的思考，我觉得Plugin部署到线上会导致函数名字变化这个问题，我真的不能忍（或许我就是巨蟹座的强迫症吧，哈哈哈），而且，我个人认为，我未必就能需要到更多的功能，例如invoke，例如metrics等。所以我选择了Components来做这个项目。</p>\n<h3 id=\"造轮子：全局变量组件\"><a href=\"#%E9%80%A0%E8%BD%AE%E5%AD%90%EF%BC%9A%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%BB%84%E4%BB%B6\" 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>造轮子：全局变量组件</h3>\n<p>说到Components做这项目，我就遇到了第一个难题，我的配置文件怎么办？我有很多的配置，我难道要在每个函数中写一遍？</p>\n<p>于是，我做了一个新的：<a href=\"https://www.npmjs.com/package/serverless-global\">serverless-global</a>，是的，这个Components的功能，或者价值就是可以满足我全局变量的需求，例如这样写我的全局变量：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"45787928010247630000\"\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    mysql_host: gz-cdb-mytest.sql.tencentcdb.com\n    mysql_user: mytest\n    mysql_password: mytest\n    mysql_port: 62580\n    mysql_db: mytest\n    mini_program_app_id: mytest\n    mini_program_app_secret: mytest`, `45787928010247630000`)\"\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\">mysql_host</span><span class=\"token punctuation\">:</span> gz<span class=\"token punctuation\">-</span>cdb<span class=\"token punctuation\">-</span>mytest.sql.tencentcdb.com\n    <span class=\"token key atrule\">mysql_user</span><span class=\"token punctuation\">:</span> mytest\n    <span class=\"token key atrule\">mysql_password</span><span class=\"token punctuation\">:</span> mytest\n    <span class=\"token key atrule\">mysql_port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">62580</span>\n    <span class=\"token key atrule\">mysql_db</span><span class=\"token punctuation\">:</span> mytest\n    <span class=\"token key atrule\">mini_program_app_id</span><span class=\"token punctuation\">:</span> mytest\n    <span class=\"token key atrule\">mini_program_app_secret</span><span class=\"token punctuation\">:</span> mytest</code></pre></div>\n<p>在使用的时候，只需要使用<code class=\"language-text\">${}</code>就可以引用，例如：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"12758542196089162000\"\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(`Album_Login:\n  component: &quot;@serverless/tencent-scf&quot;\n  inputs:\n    name: Album_Login\n    codeUri: ./album/login\n    handler: index.main_handler\n    runtime: Python3.6\n    region: ap-shanghai\n    environment:\n      variables:\n        mysql_host: \\${Conf.mysql_host}\n        mysql_port: \\${Conf.mysql_port}\n        mysql_user: \\${Conf.mysql_user}\n        mysql_password: \\${Conf.mysql_password}\n        mysql_db: \\${Conf.mysql_db}`, `12758542196089162000`)\"\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\">Album_Login</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> Album_Login\n    <span class=\"token key atrule\">codeUri</span><span class=\"token punctuation\">:</span> ./album/login\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> index.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> ap<span class=\"token punctuation\">-</span>shanghai\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\">mysql_host</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.mysql_host<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">mysql_port</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.mysql_port<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">mysql_user</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.mysql_user<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">mysql_password</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.mysql_password<span class=\"token punctuation\">}</span>\n        <span class=\"token key atrule\">mysql_db</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.mysql_db<span class=\"token punctuation\">}</span></code></pre></div>\n<p>这样，我就可以很简单轻松加愉快的，将我的配置信息统一提取到了一个配置的地方。另外这里说一下，我为啥要把一些配置信息放在环境变量，而不是统一放在一个配置文件中，因为环境变量在SCF中，会真的打到环境中，也就是说，你可以直接取到，我个人觉得比每次创建实例读取一次配置文件可能要性能好一些，可能只会好几毫秒，但是，我还是觉得这样做是比较优雅的。最主要的是，相比写到代码中和配置到单独的配置文件中，我这样做之后，我可以分享我的代码给别人，可以更好的保护的我的一些敏感信息。</p>\n<h3 id=\"数据库设计\"><a href=\"#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1\" 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>数据库设计</h3>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-13.png\"></p>\n<p>数据库部分主要对相关的表和表之间的关系进行建立。\n首先需要创建项目所必须的表：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"70725106474740015000\"\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(`CREATE DATABASE \\`album\\`;\nCREATE TABLE \\`album\\`.\\`tags\\` ( \\`tid\\` INT NOT NULL AUTO_INCREMENT , \\`name\\` VARCHAR(255) NOT NULL , \\`remark\\` TEXT NULL , PRIMARY KEY (\\`tid\\`)) ENGINE = InnoDB;\nCREATE TABLE \\`album\\`.\\`category\\` ( \\`cid\\` INT NOT NULL AUTO_INCREMENT , \\`name\\` VARCHAR(255) NOT NULL , \\`sorted\\` INT NOT NULL DEFAULT '1' , \\`user\\` INT NOT NULL , \\`remark\\` TEXT NULL , \\`publish\\` DATE NOT NULL , \\`area\\` VARCHAR(255) NULL , PRIMARY KEY (\\`cid\\`)) ENGINE = InnoDB;\nCREATE TABLE \\`album\\`.\\`users\\` ( \\`uid\\` INT NOT NULL AUTO_INCREMENT , \\`nickname\\` TEXT NOT NULL , \\`wechat\\` VARCHAR(255) NOT NULL , \\`remark\\` TEXT NULL , PRIMARY KEY (\\`uid\\`)) ENGINE = InnoDB;\nCREATE TABLE \\`album\\`.\\`photo\\` ( \\`pid\\` INT NOT NULL AUTO_INCREMENT , \\`name\\` VARCHAR(255) NOT NULL , \\`small\\` VARCHAR(255) NOT NULL , \\`large\\` VARCHAR(255) NOT NULL , \\`category\\` INT NOT NULL , \\`tags\\` VARCHAR(255) NULL , \\`remark\\` TEXT NULL , \\`creattime\\` DATE NOT NULL , \\`creatarea\\` VARCHAR(255) NOT NULL , \\`user\\` INT NOT NULL ,  PRIMARY KEY (\\`pid\\`)) ENGINE = InnoDB;\nCREATE TABLE \\`album\\`.\\`photo_tags\\` ( \\`ptid\\` INT NOT NULL AUTO_INCREMENT , \\`tag\\` INT NOT NULL , \\`photo\\` INT NOT NULL , \\`remark\\` INT NULL , PRIMARY KEY (\\`ptid\\`)) ENGINE = InnoDB;`, `70725106474740015000`)\"\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=\"mysql\"><pre class=\"language-mysql\"><code class=\"language-mysql\">CREATE DATABASE `album`;\nCREATE TABLE `album`.`tags` ( `tid` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NOT NULL , `remark` TEXT NULL , PRIMARY KEY (`tid`)) ENGINE = InnoDB;\nCREATE TABLE `album`.`category` ( `cid` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NOT NULL , `sorted` INT NOT NULL DEFAULT &#39;1&#39; , `user` INT NOT NULL , `remark` TEXT NULL , `publish` DATE NOT NULL , `area` VARCHAR(255) NULL , PRIMARY KEY (`cid`)) ENGINE = InnoDB;\nCREATE TABLE `album`.`users` ( `uid` INT NOT NULL AUTO_INCREMENT , `nickname` TEXT NOT NULL , `wechat` VARCHAR(255) NOT NULL , `remark` TEXT NULL , PRIMARY KEY (`uid`)) ENGINE = InnoDB;\nCREATE TABLE `album`.`photo` ( `pid` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(255) NOT NULL , `small` VARCHAR(255) NOT NULL , `large` VARCHAR(255) NOT NULL , `category` INT NOT NULL , `tags` VARCHAR(255) NULL , `remark` TEXT NULL , `creattime` DATE NOT NULL , `creatarea` VARCHAR(255) NOT NULL , `user` INT NOT NULL ,  PRIMARY KEY (`pid`)) ENGINE = InnoDB;\nCREATE TABLE `album`.`photo_tags` ( `ptid` INT NOT NULL AUTO_INCREMENT , `tag` INT NOT NULL , `photo` INT NOT NULL , `remark` INT NULL , PRIMARY KEY (`ptid`)) ENGINE = InnoDB;</code></pre></div>\n<p>创建之后，逐步添加表之间的关系以及部分限制条件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"85963144181079620000\"\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(`ALTER TABLE \\`photo_tags\\` ADD CONSTRAINT \\`photo_tags_tags_alter\\` FOREIGN KEY (\\`tag\\`) REFERENCES \\`tags\\`(\\`tid\\`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE \\`photo_tags\\` ADD CONSTRAINT \\`photo_tags_photo_alter\\` FOREIGN KEY (\\`photo\\`) REFERENCES \\`photo\\`(\\`pid\\`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE \\`photo\\` ADD CONSTRAINT \\`photo_category_alter\\` FOREIGN KEY (\\`category\\`) REFERENCES \\`category\\`(\\`cid\\`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE \\`photo\\` ADD CONSTRAINT \\`photo_user_alter\\` FOREIGN KEY (\\`user\\`) REFERENCES \\`users\\`(\\`uid\\`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE \\`category\\` ADD CONSTRAINT \\`category_user_alter\\` FOREIGN KEY (\\`user\\`) REFERENCES \\`users\\`(\\`uid\\`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE \\`tags\\` ADD unique(\\`name\\`);`, `85963144181079620000`)\"\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=\"mysql\"><pre class=\"language-mysql\"><code class=\"language-mysql\">ALTER TABLE `photo_tags` ADD CONSTRAINT `photo_tags_tags_alter` FOREIGN KEY (`tag`) REFERENCES `tags`(`tid`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE `photo_tags` ADD CONSTRAINT `photo_tags_photo_alter` FOREIGN KEY (`photo`) REFERENCES `photo`(`pid`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE `photo` ADD CONSTRAINT `photo_category_alter` FOREIGN KEY (`category`) REFERENCES `category`(`cid`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE `photo` ADD CONSTRAINT `photo_user_alter` FOREIGN KEY (`user`) REFERENCES `users`(`uid`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE `category` ADD CONSTRAINT `category_user_alter` FOREIGN KEY (`user`) REFERENCES `users`(`uid`) ON DELETE CASCADE ON UPDATE RESTRICT;\nALTER TABLE `tags` ADD unique(`name`);</code></pre></div>\n<h3 id=\"函数功能开发\"><a href=\"#%E5%87%BD%E6%95%B0%E5%8A%9F%E8%83%BD%E5%BC%80%E5%8F%91\" 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>函数功能开发</h3>\n<p>写完了这个部分部分，我开始着手写我的第一个函数，注册登录函数。因为这是一个小程序，所以可以认为，注册登录实际上就是拿着用户的openId去数据库查查有没有信息，有信息的话，就执行登录，没有信息的话就insert一下。那么问题来了，我这里要怎么连接我的数据库？之所以有这样的问题，是源自两个因素：</p>\n<ul>\n<li>我们平时做项目更多时候都不是每次连接一次数据库，很多时候，数据库的连接是可以保持下来的，但是Serverless架构下可以么？或者我们需要去哪里连接数据库呢？</li>\n<li>传统项目，我们做数据库连接等，是只有一个方法就可以搞定，但是函数中，每个函数都是单独存在的，我们每个函数都要连接一下数据库？</li>\n</ul>\n<h4 id=\"初始化资源探索\"><a href=\"#%E5%88%9D%E5%A7%8B%E5%8C%96%E8%B5%84%E6%BA%90%E6%8E%A2%E7%B4%A2\" 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>初始化资源探索</h4>\n<p>针对问题1，我们来做一个实验，我去腾讯云云函数创建一个test：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-9.png\"></p>\n<p>创建之后，我们疯狂点击测试按钮，多次记录运行日志：</p>\n<p>第一次</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"708977514086850400\"\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(`START RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\nEvent RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\n11111111\n\n222222222\n\n\nEND RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\nReport RequestId: 4facbf59-3787-11ea-8026-52540029942f Duration:1ms Memory:128MB MaxMemoryUsed:27.3164MB`, `708977514086850400`)\"\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=\"text\"><pre class=\"language-text\"><code class=\"language-text\">START RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\nEvent RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\n11111111\n\n222222222\n\n\nEND RequestId: 4facbf59-3787-11ea-8026-52540029942f\n\nReport RequestId: 4facbf59-3787-11ea-8026-52540029942f Duration:1ms Memory:128MB MaxMemoryUsed:27.3164MB</code></pre></div>\n<p>第二次</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"33136079816224952000\"\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(`START RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\nEvent RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\n222222222\n\n\nEND RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\nReport RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB`, `33136079816224952000`)\"\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=\"text\"><pre class=\"language-text\"><code class=\"language-text\">START RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\nEvent RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\n222222222\n\n\nEND RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d\n\nReport RequestId: 7aaf7921-3787-11ea-aba7-525400e4521d Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB</code></pre></div>\n<p>第三次</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"55604485901521000000\"\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(`START RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\nEvent RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\n222222222\n\n\nEND RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\nReport RequestId: 742be57a-3787-11ea-b5c5-52540047de0f Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB`, `55604485901521000000`)\"\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=\"text\"><pre class=\"language-text\"><code class=\"language-text\">START RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\nEvent RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\n222222222\n\n\nEND RequestId: 742be57a-3787-11ea-b5c5-52540047de0f\n\nReport RequestId: 742be57a-3787-11ea-b5c5-52540047de0f Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB</code></pre></div>\n<p>第四次</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"48507460989268255000\"\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(`START RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\nEvent RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\n222222222\n\n\nEND RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\nReport RequestId: 6faf934b-3787-11ea-8026-52540029942f Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB`, `48507460989268255000`)\"\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=\"text\"><pre class=\"language-text\"><code class=\"language-text\">START RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\nEvent RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\n222222222\n\n\nEND RequestId: 6faf934b-3787-11ea-8026-52540029942f\n\nReport RequestId: 6faf934b-3787-11ea-8026-52540029942f Duration:1ms Memory:128MB MaxMemoryUsed:27.1953MB</code></pre></div>\n<p>发现了什么？我在函数外侧写的<code class=\"language-text\">print(&quot;11111111&quot;)</code>实际上只出现了一次，也就是说他只运行了一次，而函数内的<code class=\"language-text\">print(&quot;222222222&quot;)</code>则是出现了多次，确切来说是每次都会出现，函数在创建的时候，会让我们写一个执行方法，例如<code class=\"language-text\">index.main_handler</code>，就是说默认的入口文件就是<code class=\"language-text\">index.py</code>下的<code class=\"language-text\">main_handler</code>方法。通过我们刚才的这个小实验，是不是可以认为，云函数实际上是随着机器或者容器启动同时启动了一个进程（这个时候会走一次外围的一些代码逻辑），然后当函数执行的时候，会走我们指定的方法，当函数执行完，这个容器并不会被马上销毁，而是进入销毁的倒计时，这个时候如果有请求来了，那么很可能复用这个容器，此时就没有容器启动的说法，会直接执行我们的方法。</p>\n<p>按照这个逻辑，是不是我们的函数，如果要在我们的方法之外，初始化数据库，就可以保证尽可能少的数据库连接建立，而满足更多的请求呢？换句话说，是不是和容器复用类似，我们就可以复用数据库的连接了？</p>\n<p>所以，我这里可以可以这样写我的整个代码（login 为例）</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"52967993894145884000\"\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 -*-\n\nimport os\nimport pymysql\nimport json\n\nconnection = pymysql.connect(host=os.environ.get('mysql_host'),\n                             user=&quot;root&quot;,\n                             password=os.environ.get('mysql_password'),\n                             port=int(62580),\n                             db=&quot;mini_album&quot;,\n                             charset='utf8',\n                             cursorclass=pymysql.cursors.DictCursor,\n                             autocommit=1)\n\ndef getUserInfor(connection, wecaht):\n    try:\n        connection.ping(reconnect=True)\n        cursor = connection.cursor()\n        search_stmt = (\n            &quot;SELECT * FROM \\`users\\` WHERE \\`wechat\\`=%s&quot;\n        )\n        data = (wecaht)\n        cursor.execute(search_stmt, data)\n        cursor.close()\n        result = cursor.fetchall()\n        return len(result)\n    except Exception as e:\n        print(&quot;getUserInfor&quot;, e)\n        try:\n            cursor.close()\n        except:\n            pass\n        return False\n\ndef addUseerInfor(connection, wecaht, nickname, remark):\n    try:\n        connection.ping(reconnect=True)\n        cursor = connection.cursor()\n        insert_stmt = (\n            &quot;INSERT INTO users(wechat,nickname,remark) &quot;\n            &quot;VALUES (%s,%s,%s)&quot;\n        )\n        data = (wecaht, nickname, remark)\n        cursor.execute(insert_stmt, data)\n        cursor.close()\n        connection.close()\n        return True\n    except Exception as e:\n        print(e)\n        try:\n            cursor.close()\n        except:\n            pass\n        return False\n\n\ndef main_handler(event, context):\n    print(event)\n    body = json.loads(event['body'])\n    wecaht = body['wechat']\n    nickname = body['nickname']\n    remark = str(body['remark'])\n\n    if getUserInfor(connection, wecaht) == 0:\n        if addUseerInfor(connection, wecaht, nickname, remark):\n            result = True\n        else:\n            result = False\n    else:\n        result = True\n\n    return {\n        &quot;result&quot;: result\n    }`, `52967993894145884000`)\"\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\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">import</span> pymysql\n<span class=\"token keyword\">import</span> json\n\nconnection <span class=\"token operator\">=</span> pymysql<span class=\"token punctuation\">.</span>connect<span class=\"token punctuation\">(</span>host<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\">'mysql_host'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                             user<span class=\"token operator\">=</span><span class=\"token string\">\"root\"</span><span class=\"token punctuation\">,</span>\n                             password<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\">'mysql_password'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                             port<span class=\"token operator\">=</span><span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span><span class=\"token number\">62580</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                             db<span class=\"token operator\">=</span><span class=\"token string\">\"mini_album\"</span><span class=\"token punctuation\">,</span>\n                             charset<span class=\"token operator\">=</span><span class=\"token string\">'utf8'</span><span class=\"token punctuation\">,</span>\n                             cursorclass<span class=\"token operator\">=</span>pymysql<span class=\"token punctuation\">.</span>cursors<span class=\"token punctuation\">.</span>DictCursor<span class=\"token punctuation\">,</span>\n                             autocommit<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">getUserInfor</span><span class=\"token punctuation\">(</span>connection<span class=\"token punctuation\">,</span> wecaht<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n        connection<span class=\"token punctuation\">.</span>ping<span class=\"token punctuation\">(</span>reconnect<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n        cursor <span class=\"token operator\">=</span> connection<span class=\"token punctuation\">.</span>cursor<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        search_stmt <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token string\">\"SELECT * FROM `users` WHERE `wechat`=%s\"</span>\n        <span class=\"token punctuation\">)</span>\n        data <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>wecaht<span class=\"token punctuation\">)</span>\n        cursor<span class=\"token punctuation\">.</span>execute<span class=\"token punctuation\">(</span>search_stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n        cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        result <span class=\"token operator\">=</span> cursor<span class=\"token punctuation\">.</span>fetchall<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> <span class=\"token builtin\">len</span><span class=\"token punctuation\">(</span>result<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">except</span> Exception <span class=\"token keyword\">as</span> e<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"getUserInfor\"</span><span class=\"token punctuation\">,</span> e<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n            cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">pass</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">addUseerInfor</span><span class=\"token punctuation\">(</span>connection<span class=\"token punctuation\">,</span> wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n        connection<span class=\"token punctuation\">.</span>ping<span class=\"token punctuation\">(</span>reconnect<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n        cursor <span class=\"token operator\">=</span> connection<span class=\"token punctuation\">.</span>cursor<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        insert_stmt <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token string\">\"INSERT INTO users(wechat,nickname,remark) \"</span>\n            <span class=\"token string\">\"VALUES (%s,%s,%s)\"</span>\n        <span class=\"token punctuation\">)</span>\n        data <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span>\n        cursor<span class=\"token punctuation\">.</span>execute<span class=\"token punctuation\">(</span>insert_stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n        cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        connection<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">True</span>\n    <span class=\"token keyword\">except</span> Exception <span class=\"token keyword\">as</span> e<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n            cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">pass</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</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>event<span class=\"token punctuation\">)</span>\n    body <span class=\"token operator\">=</span> json<span class=\"token punctuation\">.</span>loads<span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">[</span><span class=\"token string\">'body'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n    wecaht <span class=\"token operator\">=</span> body<span class=\"token punctuation\">[</span><span class=\"token string\">'wechat'</span><span class=\"token punctuation\">]</span>\n    nickname <span class=\"token operator\">=</span> body<span class=\"token punctuation\">[</span><span class=\"token string\">'nickname'</span><span class=\"token punctuation\">]</span>\n    remark <span class=\"token operator\">=</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>body<span class=\"token punctuation\">[</span><span class=\"token string\">'remark'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">if</span> getUserInfor<span class=\"token punctuation\">(</span>connection<span class=\"token punctuation\">,</span> wecaht<span class=\"token punctuation\">)</span> <span class=\"token operator\">==</span> <span class=\"token number\">0</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">if</span> addUseerInfor<span class=\"token punctuation\">(</span>connection<span class=\"token punctuation\">,</span> wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n            result <span class=\"token operator\">=</span> <span class=\"token boolean\">True</span>\n        <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>\n            result <span class=\"token operator\">=</span> <span class=\"token boolean\">False</span>\n    <span class=\"token keyword\">else</span><span class=\"token punctuation\">:</span>\n        result <span class=\"token operator\">=</span> <span class=\"token boolean\">True</span>\n\n    <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"result\"</span><span class=\"token punctuation\">:</span> result\n    <span class=\"token punctuation\">}</span></code></pre></div>\n<h4 id=\"公共组件的编写\"><a href=\"#%E5%85%AC%E5%85%B1%E7%BB%84%E4%BB%B6%E7%9A%84%E7%BC%96%E5%86%99\" 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>公共组件的编写</h4>\n<ul>\n<li>这个函数，我要作为小程序的一个接口，那么就要接APIGW，那么我应该怎么赖在本地测试呢？难不成每次都发到线上配置APIGW触发器才能测试，我的天，太恶心了吧！</li>\n<li>这个函数需要数据库的连接，需要获取用户的信息等，难道别的函数不需要么？如果需要也要每个函数都要重复写这部分代码？或者说，代码的复用应该如何处理呢？是否可以提取公共组件呢？</li>\n</ul>\n<p>所以，我这里将这个函数，规范化和完整化：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"10215758482289084000\"\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 -*-\n\nimport json\n\ntry:\n    import returnCommon\n    from mysqlCommon import mysqlCommon\nexcept:\n    import common.testCommon\n\n    common.testCommon.setEnv()\n\n    import common.returnCommon as returnCommon\n    from common.mysqlCommon import mysqlCommon\n\n\nmysql = mysqlCommon()\n\n\ndef main_handler(event, context):\n    try:\n        print(event)\n\n        body = json.loads(event['body'])\n\n        wecaht = body['wechat']\n        nickname = body['nickname']\n        remark = str(body['remark'])\n\n        if not wecaht:\n            return returnCommon.return_msg(True, &quot;请使用微信小程序登陆本页面。&quot;)\n\n        if not mysql.getUserInfor(wecaht):\n            if not nickname:\n                return returnCommon.return_msg(True, &quot;参数异常，请重试。&quot;)\n            if mysql.addUserInfor(wecaht, nickname, remark):\n                return returnCommon.return_msg(False, &quot;注册成功&quot;)\n            return returnCommon.return_msg(True, &quot;注册失败，请重试。&quot;)\n        return returnCommon.return_msg(False, &quot;登录成功&quot;)\n    except Exception as e:\n        print(e)\n    return returnCommon.return_msg(True, &quot;用户信息异常，请联系管理员处理&quot;)\n\ndef test():\n    event = {\n        &quot;requestContext&quot;: {\n            &quot;serviceId&quot;: &quot;service-f94sy04v&quot;,\n            &quot;path&quot;: &quot;/test/{path}&quot;,\n            &quot;httpMethod&quot;: &quot;POST&quot;,\n            &quot;requestId&quot;: &quot;c6af9ac6-7b61-11e6-9a41-93e8deadbeef&quot;,\n            &quot;identity&quot;: {\n                &quot;secretId&quot;: &quot;abdcdxxxxxxxsdfs&quot;\n            },\n            &quot;sourceIp&quot;: &quot;14.17.22.34&quot;,\n            &quot;stage&quot;: &quot;release&quot;\n        },\n        &quot;headers&quot;: {\n            &quot;Accept-Language&quot;: &quot;en-US,en,cn&quot;,\n            &quot;Accept&quot;: &quot;text/html,application/xml,application/json&quot;,\n            &quot;Host&quot;: &quot;service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com&quot;,\n            &quot;User-Agent&quot;: &quot;User Agent String&quot;\n        },\n        &quot;body&quot;: json.dumps({\n            &quot;wechat&quot;: &quot;12345&quot;,\n            &quot;nickname&quot;: &quot;test&quot;,\n            &quot;remark&quot;: &quot;&quot;,\n        }),\n        &quot;pathParameters&quot;: {\n            &quot;path&quot;: &quot;value&quot;\n        },\n        &quot;queryStringParameters&quot;: {\n            &quot;foo&quot;: &quot;bar&quot;\n        },\n        &quot;headerParameters&quot;: {\n            &quot;Refer&quot;: &quot;10.0.2.14&quot;\n        },\n        &quot;stageVariables&quot;: {\n            &quot;stage&quot;: &quot;release&quot;\n        },\n        &quot;path&quot;: &quot;/test/value&quot;,\n        &quot;queryString&quot;: {\n            &quot;foo&quot;: &quot;bar&quot;,\n            &quot;bob&quot;: &quot;alice&quot;\n        },\n        &quot;httpMethod&quot;: &quot;POST&quot;\n    }\n    print(main_handler(event, None))\n\n\nif __name__ == &quot;__main__&quot;:\n    test()`, `10215758482289084000`)\"\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\n<span class=\"token keyword\">import</span> json\n\n<span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> returnCommon\n    <span class=\"token keyword\">from</span> mysqlCommon <span class=\"token keyword\">import</span> mysqlCommon\n<span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> common<span class=\"token punctuation\">.</span>testCommon\n\n    common<span class=\"token punctuation\">.</span>testCommon<span class=\"token punctuation\">.</span>setEnv<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">import</span> common<span class=\"token punctuation\">.</span>returnCommon <span class=\"token keyword\">as</span> returnCommon\n    <span class=\"token keyword\">from</span> common<span class=\"token punctuation\">.</span>mysqlCommon <span class=\"token keyword\">import</span> mysqlCommon\n\n\nmysql <span class=\"token operator\">=</span> mysqlCommon<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\">try</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">)</span>\n\n        body <span class=\"token operator\">=</span> json<span class=\"token punctuation\">.</span>loads<span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">[</span><span class=\"token string\">'body'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n        wecaht <span class=\"token operator\">=</span> body<span class=\"token punctuation\">[</span><span class=\"token string\">'wechat'</span><span class=\"token punctuation\">]</span>\n        nickname <span class=\"token operator\">=</span> body<span class=\"token punctuation\">[</span><span class=\"token string\">'nickname'</span><span class=\"token punctuation\">]</span>\n        remark <span class=\"token operator\">=</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>body<span class=\"token punctuation\">[</span><span class=\"token string\">'remark'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> wecaht<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"请使用微信小程序登陆本页面。\"</span><span class=\"token punctuation\">)</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> mysql<span class=\"token punctuation\">.</span>getUserInfor<span class=\"token punctuation\">(</span>wecaht<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">if</span> <span class=\"token keyword\">not</span> nickname<span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"参数异常，请重试。\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">if</span> mysql<span class=\"token punctuation\">.</span>addUserInfor<span class=\"token punctuation\">(</span>wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"注册成功\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"注册失败，请重试。\"</span><span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">False</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"登录成功\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">except</span> Exception <span class=\"token keyword\">as</span> e<span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> returnCommon<span class=\"token punctuation\">.</span>return_msg<span class=\"token punctuation\">(</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"用户信息异常，请联系管理员处理\"</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    event <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"requestContext\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"serviceId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"service-f94sy04v\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"/test/{path}\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"httpMethod\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"requestId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"c6af9ac6-7b61-11e6-9a41-93e8deadbeef\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"identity\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token string\">\"secretId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"abdcdxxxxxxxsdfs\"</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"sourceIp\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"14.17.22.34\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"stage\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"release\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"headers\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"Accept-Language\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"en-US,en,cn\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"Accept\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"text/html,application/xml,application/json\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"Host\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"User-Agent\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"User Agent String\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"body\"</span><span class=\"token punctuation\">:</span> json<span class=\"token punctuation\">.</span>dumps<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"wechat\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"12345\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"nickname\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"remark\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"pathParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"value\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"queryStringParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"foo\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"bar\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"headerParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"Refer\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"10.0.2.14\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"stageVariables\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"stage\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"release\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"/test/value\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"queryString\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"foo\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"bar\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"bob\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"httpMethod\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"POST\"</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>main_handler<span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> <span class=\"token boolean\">None</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n\n\n<span class=\"token keyword\">if</span> __name__ <span class=\"token operator\">==</span> <span class=\"token string\">\"__main__\"</span><span class=\"token punctuation\">:</span>\n    test<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>数据库等一些公共组件，统一放在<code class=\"language-text\">common</code>目录下，例如<code class=\"language-text\">mysqlCommon.py</code>(部分):</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"88765757746232740000\"\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 -*-\n\nimport os\nimport random\nimport pymysql\nimport datetime\n\ntry:\n    import cosClient\nexcept:\n    import common.cosClient as cosClient\n\n\nclass mysqlCommon:\n    def __init__(self):\n        self.getConnection({\n            &quot;host&quot;: os.environ.get('mysql_host'),\n            &quot;user&quot;: os.environ.get('mysql_user'),\n            &quot;port&quot;: int(os.environ.get('mysql_port')),\n            &quot;db&quot;: os.environ.get('mysql_db'),\n            &quot;password&quot;: os.environ.get('mysql_password')\n        })\n\n    def getConnection(self, conf):\n        self.connection = pymysql.connect(host=conf['host'],\n                                          user=conf['user'],\n                                          password=conf['password'],\n                                          port=int(conf['port']),\n                                          db=conf['db'],\n                                          charset='utf8',\n                                          cursorclass=pymysql.cursors.DictCursor,\n                                          autocommit=1)\n\n    def doAction(self, stmt, data):\n        try:\n            self.connection.ping(reconnect=True)\n            cursor = self.connection.cursor()\n            cursor.execute(stmt, data)\n            result = cursor\n            cursor.close()\n            return result\n        except Exception as e:\n            print(e)\n            try:\n                cursor.close()\n            except:\n                pass\n            return False\n\n    def addUserInfor(self, wecaht, nickname, remark):\n        insert_stmt = (\n            &quot;INSERT INTO users(wechat, nickname, remark) &quot;\n            &quot;VALUES (%s,%s,%s)&quot;\n        )\n        data = (wecaht, nickname, remark)\n        result = self.doAction(insert_stmt, data)\n        return False if result == False else True`, `88765757746232740000`)\"\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\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">import</span> random\n<span class=\"token keyword\">import</span> pymysql\n<span class=\"token keyword\">import</span> datetime\n\n<span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> cosClient\n<span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> common<span class=\"token punctuation\">.</span>cosClient <span class=\"token keyword\">as</span> cosClient\n\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">mysqlCommon</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">__init__</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        self<span class=\"token punctuation\">.</span>getConnection<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"host\"</span><span class=\"token punctuation\">:</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'mysql_host'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"user\"</span><span class=\"token punctuation\">:</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'mysql_user'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"port\"</span><span class=\"token punctuation\">:</span> <span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'mysql_port'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"db\"</span><span class=\"token punctuation\">:</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'mysql_db'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"password\"</span><span class=\"token punctuation\">:</span> os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">.</span>get<span class=\"token punctuation\">(</span><span class=\"token string\">'mysql_password'</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">def</span> <span class=\"token function\">getConnection</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> conf<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        self<span class=\"token punctuation\">.</span>connection <span class=\"token operator\">=</span> pymysql<span class=\"token punctuation\">.</span>connect<span class=\"token punctuation\">(</span>host<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'host'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                                          user<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'user'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                                          password<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'password'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                                          port<span class=\"token operator\">=</span><span class=\"token builtin\">int</span><span class=\"token punctuation\">(</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'port'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                                          db<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'db'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n                                          charset<span class=\"token operator\">=</span><span class=\"token string\">'utf8'</span><span class=\"token punctuation\">,</span>\n                                          cursorclass<span class=\"token operator\">=</span>pymysql<span class=\"token punctuation\">.</span>cursors<span class=\"token punctuation\">.</span>DictCursor<span class=\"token punctuation\">,</span>\n                                          autocommit<span class=\"token operator\">=</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">def</span> <span class=\"token function\">doAction</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n            self<span class=\"token punctuation\">.</span>connection<span class=\"token punctuation\">.</span>ping<span class=\"token punctuation\">(</span>reconnect<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n            cursor <span class=\"token operator\">=</span> self<span class=\"token punctuation\">.</span>connection<span class=\"token punctuation\">.</span>cursor<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            cursor<span class=\"token punctuation\">.</span>execute<span class=\"token punctuation\">(</span>stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n            result <span class=\"token operator\">=</span> cursor\n            cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> result\n        <span class=\"token keyword\">except</span> Exception <span class=\"token keyword\">as</span> e<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n                cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">pass</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span>\n\n    <span class=\"token keyword\">def</span> <span class=\"token function\">addUserInfor</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        insert_stmt <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token string\">\"INSERT INTO users(wechat, nickname, remark) \"</span>\n            <span class=\"token string\">\"VALUES (%s,%s,%s)\"</span>\n        <span class=\"token punctuation\">)</span>\n        data <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>wecaht<span class=\"token punctuation\">,</span> nickname<span class=\"token punctuation\">,</span> remark<span class=\"token punctuation\">)</span>\n        result <span class=\"token operator\">=</span> self<span class=\"token punctuation\">.</span>doAction<span class=\"token punctuation\">(</span>insert_stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span> <span class=\"token keyword\">if</span> result <span class=\"token operator\">==</span> <span class=\"token boolean\">False</span> <span class=\"token keyword\">else</span> <span class=\"token boolean\">True</span></code></pre></div>\n<p>这样做的好处是：</p>\n<ul>\n<li>我将数据库提取出一个公共组件，便于维护</li>\n<li>在login函数中，我根据不同的时期（本地开发和线上），可以导入不同的模块</li>\n</ul>\n<h4 id=\"便于开发与测试的方法\"><a href=\"#%E4%BE%BF%E4%BA%8E%E5%BC%80%E5%8F%91%E4%B8%8E%E6%B5%8B%E8%AF%95%E7%9A%84%E6%96%B9%E6%B3%95\" 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>便于开发与测试的方法</h4>\n<p>由于云函数的测试非常不友好，所以为了让编写代码时候，可以更快地模拟线上环境，可以通过增加<code class=\"language-text\">test()</code>方法来模拟触发器情况，进行简单的测试。</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"72942414654420070000\"\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(`try:\n    import cosClient\nexcept:\n    import common.cosClient as cosClient`, `72942414654420070000`)\"\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 keyword\">try</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> cosClient\n<span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">import</span> common<span class=\"token punctuation\">.</span>cosClient <span class=\"token keyword\">as</span> cosClient</code></pre></div>\n<p>这样会更加便利，同时模拟网关，做一个测试方法：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"7383420952225128000\"\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(`def test():\n    event = {\n        &quot;requestContext&quot;: {\n            &quot;serviceId&quot;: &quot;service-f94sy04v&quot;,\n            &quot;path&quot;: &quot;/test/{path}&quot;,\n            &quot;httpMethod&quot;: &quot;POST&quot;,\n            &quot;requestId&quot;: &quot;c6af9ac6-7b61-11e6-9a41-93e8deadbeef&quot;,\n            &quot;identity&quot;: {\n                &quot;secretId&quot;: &quot;abdcdxxxxxxxsdfs&quot;\n            },\n            &quot;sourceIp&quot;: &quot;14.17.22.34&quot;,\n            &quot;stage&quot;: &quot;release&quot;\n        },\n        &quot;headers&quot;: {\n            &quot;Accept-Language&quot;: &quot;en-US,en,cn&quot;,\n            &quot;Accept&quot;: &quot;text/html,application/xml,application/json&quot;,\n            &quot;Host&quot;: &quot;service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com&quot;,\n            &quot;User-Agent&quot;: &quot;User Agent String&quot;\n        },\n        &quot;body&quot;: json.dumps({\n            &quot;wechat&quot;: &quot;12345&quot;,\n            &quot;nickname&quot;: &quot;test&quot;,\n            &quot;remark&quot;: &quot;&quot;,\n        }),\n        &quot;pathParameters&quot;: {\n            &quot;path&quot;: &quot;value&quot;\n        },\n        &quot;queryStringParameters&quot;: {\n            &quot;foo&quot;: &quot;bar&quot;\n        },\n        &quot;headerParameters&quot;: {\n            &quot;Refer&quot;: &quot;10.0.2.14&quot;\n        },\n        &quot;stageVariables&quot;: {\n            &quot;stage&quot;: &quot;release&quot;\n        },\n        &quot;path&quot;: &quot;/test/value&quot;,\n        &quot;queryString&quot;: {\n            &quot;foo&quot;: &quot;bar&quot;,\n            &quot;bob&quot;: &quot;alice&quot;\n        },\n        &quot;httpMethod&quot;: &quot;POST&quot;\n    }\n    print(main_handler(event, None))`, `7383420952225128000`)\"\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 keyword\">def</span> <span class=\"token function\">test</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    event <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">\"requestContext\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"serviceId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"service-f94sy04v\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"/test/{path}\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"httpMethod\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"POST\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"requestId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"c6af9ac6-7b61-11e6-9a41-93e8deadbeef\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"identity\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token string\">\"secretId\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"abdcdxxxxxxxsdfs\"</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"sourceIp\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"14.17.22.34\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"stage\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"release\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"headers\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"Accept-Language\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"en-US,en,cn\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"Accept\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"text/html,application/xml,application/json\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"Host\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"User-Agent\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"User Agent String\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"body\"</span><span class=\"token punctuation\">:</span> json<span class=\"token punctuation\">.</span>dumps<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"wechat\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"12345\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"nickname\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"test\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"remark\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"pathParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"value\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"queryStringParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"foo\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"bar\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"headerParameters\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"Refer\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"10.0.2.14\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"stageVariables\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"stage\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"release\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"path\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"/test/value\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"queryString\"</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">\"foo\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"bar\"</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">\"bob\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"alice\"</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"httpMethod\"</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"POST\"</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>main_handler<span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> <span class=\"token boolean\">None</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>增加本地测试时，指定<code class=\"language-text\">test()</code>方法：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"62724596694597730000\"\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(`if __name__ == &quot;__main__&quot;:\n    test()`, `62724596694597730000`)\"\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 keyword\">if</span> __name__ <span class=\"token operator\">==</span> <span class=\"token string\">\"__main__\"</span><span class=\"token punctuation\">:</span>\n    test<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>这样，线上触发时，会默认执行<code class=\"language-text\">main_handler</code>, 而本地执行，则会通过<code class=\"language-text\">test</code>走入<code class=\"language-text\">main_handler</code>，我们可以边开发，边测试，弄好了再部署到线上。</p>\n<p>同时，我们线上获取配置信息是通过获取环境变量，那么我们本地呢？</p>\n<p>我们可以在本地执行的时候，先进行这个操作：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"72691537014664135000\"\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 -*-\n\nimport yaml\nimport os\n\n\ndef setEnv():\n    file = open(&quot;/Users/dfounderliu/Documents/code/AIAlbum/serverless.yaml&quot;, 'r', encoding=&quot;utf-8&quot;)\n    file_data = file.read()\n    file.close()\n\n    data = yaml.load(file_data)\n    for eveKey, eveValue in data['Conf']['inputs'].items():\n        print(eveKey, eveValue)\n        os.environ[eveKey] = str(eveValue)`, `72691537014664135000`)\"\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\n<span class=\"token keyword\">import</span> yaml\n<span class=\"token keyword\">import</span> os\n\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">setEnv</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    <span class=\"token builtin\">file</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">open</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/Users/dfounderliu/Documents/code/AIAlbum/serverless.yaml\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'r'</span><span class=\"token punctuation\">,</span> encoding<span class=\"token operator\">=</span><span class=\"token string\">\"utf-8\"</span><span class=\"token punctuation\">)</span>\n    file_data <span class=\"token operator\">=</span> <span class=\"token builtin\">file</span><span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token builtin\">file</span><span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n    data <span class=\"token operator\">=</span> yaml<span class=\"token punctuation\">.</span>load<span class=\"token punctuation\">(</span>file_data<span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">for</span> eveKey<span class=\"token punctuation\">,</span> eveValue <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">'Conf'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">'inputs'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>items<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>eveKey<span class=\"token punctuation\">,</span> eveValue<span class=\"token punctuation\">)</span>\n        os<span class=\"token punctuation\">.</span>environ<span class=\"token punctuation\">[</span>eveKey<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>eveValue<span class=\"token punctuation\">)</span></code></pre></div>\n<p>这样，我们这个文件就非常完美的，可以线上直接用，也可以本地直接用了！</p>\n<p>那么我们的Yaml怎么写？</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-10.png\"></p>\n<p> 是的，这样我们就可以很简单轻松加愉快的将我们的公共组件库，在部署函数的时候，引入到项目中。</p>\n<p> 本地形式：</p>\n<p><img src=\"https://img.serverlesscloud.cn/202058/3-6-11.png\"></p>\n<p> 线上形式：</p>\n<p> <img src=\"https://img.serverlesscloud.cn/202058/3-6-12.png\"></p>\n<p> 对于这个项目，完美解决本地调试，线上运行的全兼容问题。</p>\n<h4 id=\"项目部署\"><a href=\"#%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2\" 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>项目部署</h4>\n<ul>\n<li>在使用之前您需要有一个腾讯云的账号，并且开通了COS、COS、APIGW以及CDB等相关产品权限；</li>\n<li>将项目clone到本地，配置自己的密钥信息、数据库信息。配置文件在<code class=\"language-text\">cloudFunction</code>目录下的<code class=\"language-text\">serverless.yaml</code>中：</li>\n</ul>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"97425414725675190000\"\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(`# 函数们的整体配置信息\nConf:\n  component: &quot;serverless-global&quot;\n  inputs:\n    region: ap-shanghai\n    runtime: Python3.6\n    handler: index.main_handler\n    include_common: ./common\n    mysql_host: gz-c************************.com\n    mysql_user: root\n    mysql_password: S************************!\n    mysql_port: 6************************0\n    mysql_db: album\n    mini_program_app_id: asdsa************************dddd\n    mini_program_app_secret: fd340c4************************8744ee\n    tencent_secret_id: AKID1y************************l1q0kK\n    tencent_secret_key: cCoJ************************FZj5Oa\n    tencent_appid: 1256773370\n    cos_bucket: 'album-1256773370'\n    domain: album.0duzahn.com`, `97425414725675190000`)\"\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 comment\"># 函数们的整体配置信息</span>\n<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>shanghai\n    <span class=\"token key atrule\">runtime</span><span class=\"token punctuation\">:</span> Python3.6\n    <span class=\"token key atrule\">handler</span><span class=\"token punctuation\">:</span> index.main_handler\n    <span class=\"token key atrule\">include_common</span><span class=\"token punctuation\">:</span> ./common\n    <span class=\"token key atrule\">mysql_host</span><span class=\"token punctuation\">:</span> gz<span class=\"token punctuation\">-</span>c************************.com\n    <span class=\"token key atrule\">mysql_user</span><span class=\"token punctuation\">:</span> root\n    <span class=\"token key atrule\">mysql_password</span><span class=\"token punctuation\">:</span> S************************!\n    <span class=\"token key atrule\">mysql_port</span><span class=\"token punctuation\">:</span> 6***********************<span class=\"token important\">*0</span>\n    <span class=\"token key atrule\">mysql_db</span><span class=\"token punctuation\">:</span> album\n    <span class=\"token key atrule\">mini_program_app_id</span><span class=\"token punctuation\">:</span> asdsa***********************<span class=\"token important\">*dddd</span>\n    <span class=\"token key atrule\">mini_program_app_secret</span><span class=\"token punctuation\">:</span> fd340c4***********************<span class=\"token important\">*8744ee</span>\n    <span class=\"token key atrule\">tencent_secret_id</span><span class=\"token punctuation\">:</span> AKID1y***********************<span class=\"token important\">*l1q0kK</span>\n    <span class=\"token key atrule\">tencent_secret_key</span><span class=\"token punctuation\">:</span> cCoJ***********************<span class=\"token important\">*FZj5Oa</span>\n    <span class=\"token key atrule\">tencent_appid</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1256773370</span>\n    <span class=\"token key atrule\">cos_bucket</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'album-1256773370'</span>\n    <span class=\"token key atrule\">domain</span><span class=\"token punctuation\">:</span> album.0duzahn.com</code></pre></div>\n<p>由于我目前使用的是Serverless Components，没有全局变量等，所以在此处增加了全局变量组件，在这里设置好全局变量，在之后的Components中可以直接引用，例如：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"70507688187402340000\"\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(`# 创建存储桶\nCosBucket:\n  component: '@serverless/tencent-website'\n  inputs:\n    code:\n      src: ./cos\n    region:  \\${Conf.region}\n    bucketName: \\${Conf.cos_bucket}`, `70507688187402340000`)\"\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 comment\"># 创建存储桶</span>\n<span class=\"token key atrule\">CosBucket</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-website'</span>\n  <span class=\"token key atrule\">inputs</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">code</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">src</span><span class=\"token punctuation\">:</span> ./cos\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\">bucketName</span><span class=\"token punctuation\">:</span> $<span class=\"token punctuation\">{</span>Conf.cos_bucket<span class=\"token punctuation\">}</span></code></pre></div>\n<ul>\n<li>安装必备工具，例如必须要安装Serverless Framework（可以参考：<a href=\"https://cloud.tencent.com/document/product/1154/39005%EF%BC%89\">https://cloud.tencent.com/document/product/1154/39005）</a>, 同样由于本项目后台开发语言是Python，您也需要一些Python的开发工具以及包管理工具，以及小程序云开发的IDE；</li>\n<li>\n<p>在部分文件夹下安装相对应的依赖：</p>\n<ul>\n<li><code class=\"language-text\">cloudFunction/album/prdiction</code>需要安装Pillow, opencv，tensorflow，jieba</li>\n<li><code class=\"language-text\">cloudFunction/album/getPhotoSearch</code>需要安装gensim，jieba以及collections</li>\n<li><code class=\"language-text\">cloudFunction/album/compression</code>需要安装Pillow\n注意，在安装的时候一定要用CentOS操作系统，并且Python要3.6版本，如果没相对应系统，可以在这里打包对应的依赖：<a href=\"http://serverless.0duzhan.com/app/scf_python_package_download/\">http://serverless.0duzhan.com/app/scf_python_package_download/</a></li>\n</ul>\n</li>\n<li>将项目部署到云端，只需要通过指令<code class=\"language-text\">serverless --debug</code>即可：</li>\n</ul>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"38960987153279490000\"\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(`DEBUG ─ Resolving the template's static variables.\n  DEBUG ─ Collecting components from the template.\n  DEBUG ─ Downloading any NPM components found in the template.\n  DEBUG ─ Analyzing the template's components dependencies.\n  DEBUG ─ Creating the template's components graph.\n  DEBUG ─ Syncing template state.\n  DEBUG ─ Executing the template's components graph.\n  DEBUG ─ Starting API-Gateway deployment with name APIService in the ap-shanghai region\n\n    ... ...\n\n  DEBUG ─ Updating configure...\n  DEBUG ─ Created function Album_Get_Photo_Search successful\n  DEBUG ─ Setting tags for function Album_Get_Photo_Search\n  DEBUG ─ Creating trigger for function Album_Get_Photo_Search\n  DEBUG ─ Deployed function Album_Get_Photo_Search successful\n  DEBUG ─ Uploaded package successful /Users/dfounderliu/Documents/code/AIAlbum/.serverless/Album_Prediction.zip\n  DEBUG ─ Creating function Album_Prediction\n  DEBUG ─ Updating code...\n  DEBUG ─ Updating configure...\n  DEBUG ─ Created function Album_Prediction successful\n  DEBUG ─ Setting tags for function Album_Prediction\n  DEBUG ─ Creating trigger for function Album_Prediction\n  DEBUG ─ Trigger timer: timer not changed\n  DEBUG ─ Deployed function Album_Prediction successful\n\n  Conf:\n    region:                  ap-shanghai\n\n      ... ...\n\n      -\n        path:   /photo/delete\n        method: ANY\n        apiId:  api-g9u6r9wq\n      -\n        path:   /album/delete\n        method: ANY\n        apiId:  api-b4c4xrq8\n      -\n        path:   /album/add\n        method: ANY\n        apiId:  api-ml6q5koy\n\n  156s › APIService › done`, `38960987153279490000`)\"\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=\"text\"><pre class=\"language-text\"><code class=\"language-text\">DEBUG ─ Resolving the template&#39;s static variables.\n  DEBUG ─ Collecting components from the template.\n  DEBUG ─ Downloading any NPM components found in the template.\n  DEBUG ─ Analyzing the template&#39;s components dependencies.\n  DEBUG ─ Creating the template&#39;s components graph.\n  DEBUG ─ Syncing template state.\n  DEBUG ─ Executing the template&#39;s components graph.\n  DEBUG ─ Starting API-Gateway deployment with name APIService in the ap-shanghai region\n\n    ... ...\n\n  DEBUG ─ Updating configure...\n  DEBUG ─ Created function Album_Get_Photo_Search successful\n  DEBUG ─ Setting tags for function Album_Get_Photo_Search\n  DEBUG ─ Creating trigger for function Album_Get_Photo_Search\n  DEBUG ─ Deployed function Album_Get_Photo_Search successful\n  DEBUG ─ Uploaded package successful /Users/dfounderliu/Documents/code/AIAlbum/.serverless/Album_Prediction.zip\n  DEBUG ─ Creating function Album_Prediction\n  DEBUG ─ Updating code...\n  DEBUG ─ Updating configure...\n  DEBUG ─ Created function Album_Prediction successful\n  DEBUG ─ Setting tags for function Album_Prediction\n  DEBUG ─ Creating trigger for function Album_Prediction\n  DEBUG ─ Trigger timer: timer not changed\n  DEBUG ─ Deployed function Album_Prediction successful\n\n  Conf:\n    region:                  ap-shanghai\n\n      ... ...\n\n      -\n        path:   /photo/delete\n        method: ANY\n        apiId:  api-g9u6r9wq\n      -\n        path:   /album/delete\n        method: ANY\n        apiId:  api-b4c4xrq8\n      -\n        path:   /album/add\n        method: ANY\n        apiId:  api-ml6q5koy\n\n  156s › APIService › done</code></pre></div>\n<p>例如我的这个过程，只用了156s部署了所有函数，然后打开小程序的id带入<code class=\"language-text\">miniProgram</code>目录，并且填写自己的<code class=\"language-text\">appid</code>在文件<code class=\"language-text\">project.config.json</code>的第17行，同时也要配置自己项目的基础目录，就是API网关给我们返回的地址，写在<code class=\"language-text\">app.js</code>的第10行，此时项目就可以运行起来了。</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>本例子是通过Serverless架构使用Python语言开发了一个微信小程序，这里面涉及到了数据库的增删改查，公共组件的提取，知道了如何定义Components的全局变量，如何本地调试和线上触发二者兼得，以及在什么地方初始化数据库\"性价比较高\"，通过这样一个简单的例子，希望可以让Serverless在更多的领域都有实际的应用价值，可以给更多人灵感和启发：Serverless？万物都可以Serverless么？让我们一起来尝试更多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>\n<p><a href=\"/best-practice/2020-04-19-applets/#%E5%9F%BA%E7%A1%80%E8%AE%BE%E8%AE%A1\">基础设计</a></p>\n<ul>\n<li>\n<ul>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E6%B3%A8%E5%86%8C%E5%8A%9F%E8%83%BD%EF%BC%9A\">注册功能：</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E7%9B%B8%E5%86%8C%E5%8A%9F%E8%83%BD%EF%BC%9A\">相册功能：</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E5%9B%BE%E7%89%87%E5%8A%9F%E8%83%BD%EF%BC%9A\">图片功能：</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E6%90%9C%E7%B4%A2%E5%8A%9F%E8%83%BD%EF%BC%9A\">搜索功能：</a></li>\n</ul>\n</li>\n</ul>\n</li>\n<li>\n<p><a href=\"/best-practice/2020-04-19-applets/#%E9%A1%B9%E7%9B%AE%E5%BC%80%E5%8F%91\">项目开发</a></p>\n<ul>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E5%88%9D%E6%AD%A5%E4%BA%86%E8%A7%A3-serverless-cli\">初步了解 Serverless ClI</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E9%80%A0%E8%BD%AE%E5%AD%90%EF%BC%9A%E5%85%A8%E5%B1%80%E5%8F%98%E9%87%8F%E7%BB%84%E4%BB%B6\">造轮子：全局变量组件</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1\">数据库设计</a></li>\n<li>\n<p><a href=\"/best-practice/2020-04-19-applets/#%E5%87%BD%E6%95%B0%E5%8A%9F%E8%83%BD%E5%BC%80%E5%8F%91\">函数功能开发</a></p>\n<ul>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E5%88%9D%E5%A7%8B%E5%8C%96%E8%B5%84%E6%BA%90%E6%8E%A2%E7%B4%A2\">初始化资源探索</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E5%85%AC%E5%85%B1%E7%BB%84%E4%BB%B6%E7%9A%84%E7%BC%96%E5%86%99\">公共组件的编写</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E4%BE%BF%E4%BA%8E%E5%BC%80%E5%8F%91%E4%B8%8E%E6%B5%8B%E8%AF%95%E7%9A%84%E6%96%B9%E6%B3%95\">便于开发与测试的方法</a></li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2\">项目部署</a></li>\n</ul>\n</li>\n</ul>\n</li>\n<li><a href=\"/best-practice/2020-04-19-applets/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"ebea695d-436a-5cb9-955a-2be16fa5102f","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020511/1589207417716-ZalNtxgQAC_small.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-20T00:00:00.000Z","title":"Serverless 架构下，3 分钟实现文本敏感词过滤","description":"随着各种社交平台等的日益火爆，敏感词过滤逐渐成了非常重要的也是值得重视的功能。那么在 Serverless 架构下，敏感词过滤又有那些新的实现呢？","authorslink":["https://zhuanlan.zhihu.com/ServerlessGo"],"translators":null,"translatorslink":null,"tags":["Python","文本处理"],"keywords":"Serverless 多环境配置,Serverless 管理环境,Serverless配置方案","outdated":true},"wordCount":{"words":167,"sentences":44,"paragraphs":44},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-20-filter-sensitive-words.md","fields":{"slug":"/best-practice/2020-04-20-filter-sensitive-words/","keywords":["python","serverless","函数计算","self","root","关键词","敏感","time","level","word"]}},"nextBlog":{"id":"77c4bdde-d7d5-5d48-be8f-41da1800fef5","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020512/1589275221296-1656e42a0c563a4.jpg","authors":["Anycodes"],"categories":["best-practice"],"date":"2020-04-18T00: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":70,"sentences":23,"paragraphs":23},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-04-18-inquire.md","fields":{"slug":"/best-practice/2020-04-18-inquire/","keywords":["go","python","serverless","云函数","book","mui","sheet"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"99725ecb-905b-5852-a6c7-80e83df8d7f9","previousBlogId":"ebea695d-436a-5cb9-955a-2be16fa5102f","nextBlogId":"77c4bdde-d7d5-5d48-be8f-41da1800fef5"}}}