云应用-Node.js版

本文介绍如何基于 NodeJS 技术栈创建并部署一个简单的 Todo App 应用程序。

前提条件

操作步骤

整个操作流程分为以下 8 步:

创建小程序

  • 登录 蚂蚁金服开放平台,选择 开发者中心 > 小程序 > 创建
  • 填写 基本信息,点击 创建 按钮,创建应用名为 示例应用 小程序。

说明:一个账号下最多可以创建10个小程序;未提交过审核的小程序可以删除,删除的小程序不在计数范围。

创建云应用后端服务

  • 我的小程序 页面,选择刚创建的小程序,点击 查看,进入 开发管理 页面。
  • 点击左侧导航栏的 云服务(公测),在 云服务列表 页面点击 创建云服务 > 创建云应用
  • 创建云应用 页面,选择 NodeJS** 技术栈,填入 应用名称描述 (选填),点击 创建**。

构建环境

  • 返回 云服务 页面,点击刚创建的云服务卡片中的 构建环境 按钮。
  • 购买环境资源 页面,选择合适的环境配置方案,此处选择 小程序云应用入门(Mysql 版),点击 同意《产品服务协议》 > 确认配置

说明:当前测试环境该方案免费提供,但若连续 7 日未部署过代码,环境会被自动回收。

  • 确认订单 页面,点击 确认购买。购买成功后会自动进入 构建环境 页面。构建过程会耗时几分钟,构建成功后,您可以选择 查看应用详情 ,或者 返回应用列表

准备开发环境

  • 打开小程序开发者工具,点击 新建项目
    image

  • 在新建项目向导中,选择 小程序,选择 Todo App **示例,点击**下一步
    image

  • 输入 项目名称,项目路径会自动填充,选择 云应用 为后端服务,点击 完成
    image

  • 项目创建好后,进入开发界面。点击右上角的 登录 按钮,用支付宝扫码登录。
    image

  • 关联前面 创建的小程序 应用。
    image

  • 关联前面 构建的云应用环境,点击 确定

数据准备

开发后端代码之前,需要先建立应用运行所需的数据库。

  • 云应用详情 页面的 数据库 页签,点击查看**Web 控制台,登录后进入 PhpMyAdmin** 的数据库管理页面。
  • 在 sample 数据库中,新建表 task,数据结构如下。请确保表结构与图中完全一致,否则程序可能无法运行,特别是如下几处:a. 字段名称;b. 字段类型;c. id字段为主键,且自增(A_I);d. done字段默认值为0;e. 各字段是否允许空值。
    image您也可以通过执行以下SQL建表。3. sql CREATE TABLE task (id bigint(20) NOT NULL AUTO_INCREMENT,label varchar(140) CHARACTER SET utf8 DEFAULT NULL,done tinyint(1) NOT NULL DEFAULT '0',img_url varchar(256) CHARACTER SET utf8 DEFAULT NULL,user_id varchar(50) CHARACTER SET utf8 DEFAULT NULL,PRIMARY KEY (id)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf84. 点击 保存,完成创建该示例程序所需的数据库表。

开发云应用后端服务

  • 后端代码结构如下图,运行后端服务之前需要修改图中标注的几个文件。
    image

  • config/config.default.js 文件:其中的 config.mysql 对象中数据库相关的参数需修改为您创建的云应用的对应值。
    1.png

具体值可以从 云应用详情 页的 数据库 页签中得到。

1.png

  • app/controller/home.js 文件:getUserInfo 方法中初始化 AlipaySdk 对象的代码如下:
    image参数 appId、privateKey 和 alipayPublicKey 分别为小程序 ID 和应用的私钥、公钥。其中,私钥和公钥分别存储在了文件 private-key.pem 和 public-key.pem 中。

image.png小程序的ID可以在小程序页面的左上角获得。小程序应用密钥的获取方法请参看 文档。使用RSA密钥生成工具生成PKCS1格式的私钥、公钥后,将私钥内容存入 private-key.pem 文件中,再将公钥设置到开放平台,最后将生成的支付宝公钥内容存入 public-key.pem 中。

image.png此外,home.js 中还有个变量 DEMO_DOMAIN 需要修改为云应用服务所在的域名或 IP 地址。

  • 在 server 目录下,运行命令 npm install && npm run dev可在本地运行程序。
    需要注意的是,为了使用小程序服务端SDK获取用户信息,小程序 > 开发管理 > 功能列表 中,必须添加 获取会员信息 这一功能。

image.png

后端代码介绍

下面对后端代码做简单介绍。

文件 app/router.js 中定义了 url 路由。

  1. module.exports = app => {
  2. const { router, controller } = app;
  3. router.get('/', controller.home.index);
  4. router.get('/todos', controller.home.getTodos);
  5. router.get('/users', controller.home.getUserInfo);
  6. router.post('/todos/delete', controller.home.deleteTodo);
  7. router.post('/todos/change', controller.home.changeState);
  8. router.post('/todos/add', controller.home.addTodo);
  9. router.post('/upload', controller.home.upload);
  10. };

可以看到,后端服务的各接口都路由到了 app/controller/home.js 文件中的各个方法。

其中,方法 getUserInfo 拿到前端传过来的 auth code,通过 AlipaySdk 拿到 access token 后再通过 AlipaySdk 获得用户的信息。

  1. async getUserInfo() {
  2. // 拿到前端传过来的auth code
  3. const authcode = this.ctx.request.query.authcode;
  4. // 创建AlipaySdk对象
  5. const alipaySdk = new AlipaySdk({
  6. appId: 'fill in your app ID',
  7. privateKey: fs.readFileSync('./private-key.pem', 'ascii'),
  8. alipayPublicKey: fs.readFileSync('./public-key.pem', 'ascii'),
  9. });
  10. // 调用alipay.system.oauth.token方法,用auth code 换取 access token
  11. const authMethod = 'alipay.system.oauth.token';
  12. const authParams = {
  13. grant_type: 'authorization_code',
  14. code: authcode,
  15. };
  16. try {
  17. const authResult = await alipaySdk.exec(authMethod, authParams);
  18. // 调用alipay.user.info.share方法,用access token 拿到用户信息
  19. const userMethod = 'alipay.user.info.share';
  20. const userParams = {
  21. auth_token: authResult.accessToken,
  22. }
  23. const result = await alipaySdk.exec(userMethod, userParams);
  24. // 将用户信息写入返回的消息体中,返回给前端
  25. this.ctx.body = result;
  26. } catch (err) {
  27. console.log('get user info err>>>>>', err);
  28. }
  29. }

方法 getTodos 从数据库中取得某个用户的所有 todo 项,并返回给前端。MySQL 数据库访问使用了插件 egg-mysql,插件具体用法请参看 文档

  1. async getTodos() {
  2. // 从url的query中取得userId
  3. var userId = this.ctx.query.userId;
  4. var tasks;
  5. if (userId) {
  6. // 如果前端有传userId,则向数据库请求该userId下的所有task
  7. tasks = await this.app.mysql.select('task', {
  8. where: {user_id: userId}
  9. });
  10. } else {
  11. // 如果前端没有传userId,则返回数据库中所有的task
  12. tasks = await this.app.mysql.select('task');
  13. }
  14. // 将task转换成前端所需的格式
  15. const todos = tasks.map(item => {return {
  16. text: item.label,
  17. completed: (item.done > 0 ? true : false),
  18. id: item.id,
  19. iconUrl: item.img_url
  20. }});
  21. // 将todo项写入消息体,返回给前端
  22. this.ctx.body = {
  23. success: true,
  24. todoList: todos
  25. };
  26. }

方法 upload 接收前端上传的文件,并存到默认的静态资源目录中(app/public)。

  1. async upload() {
  2. // 从请求中获取文件流
  3. const { ctx } = this;
  4. const stream = await ctx.getFileStream();
  5. // 生成文件名( UPLOAD_DIR 为存储上传图片的文件夹,该文件夹必须存在)
  6. var fileId = uuid.v1() + path.extname(stream.filename);
  7. const name = UPLOAD_DIR + '/' + fileId;
  8. try {
  9. // 处理文件
  10. stream.pipe(fs.createWriteStream(name));
  11. } catch(err) {
  12. console.log('pipe error!', err);
  13. // 将上传的文件流消费掉,不然浏览器响应会卡死
  14. await sendToWormhole(stream);
  15. throw err;
  16. }
  17. // 返回上传图片的访问地址,DEMO_DOMAIN 为云应用域名
  18. ctx.body = {
  19. imgUrl: 'https://' + DEMO_DOMAIN +'/public/' + fileId,
  20. };
  21. }

开发小程序前端界面

关于 Todo App 前端代码的详细介绍参见 文档。前端代码结构如下图。

image

其中 app.js 文件中的变量 demoDomain 需要修改为您自己的小程序云应用的域名,该域名可以从 云应用详情 页的 二级域名 页签中复制得到。

image

发布部署应用

  • 点开 云服务 右边的菜单,点击 上传服务端代码
    image上传及发布过程中,可以通过 查看日志 关注部署进度。

image

image

  • 部署完成后,在小程序开发者工具中编译应用,即可查看程序运行效果。
    image测试完成后,点击页面右上角的 上传 按钮将小程序上传到开放平台,也可以点击 预览,用手机支付宝 APP 扫码预览在手机上的真实效果。若要在手机上向服务器发送请求,您还需要到 小程序管理 页面 > 设置 > httpRequest 接口请求域名白名单,把 HTTP 请求的域名录入进去。

image

  • 上传完毕后,登录到开放平台提交审核。审核完毕后,小程序即可进行发布操作了。

原文: https://docs.alipay.com/mini/developer/todo-nodejs