{"id":13654394,"url":"https://github.com/CFETeam/weapp-demo-session","last_synced_at":"2025-04-23T09:33:27.477Z","repository":{"id":75541685,"uuid":"69313324","full_name":"CFETeam/weapp-demo-session","owner":"CFETeam","description":"The weapp-session demo of wechat micro program","archived":false,"fork":false,"pushed_at":"2016-11-04T09:08:04.000Z","size":56,"stargazers_count":119,"open_issues_count":0,"forks_count":27,"subscribers_count":21,"default_branch":"master","last_synced_at":"2024-11-10T06:32:15.386Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CFETeam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-09-27T02:54:02.000Z","updated_at":"2024-01-25T21:29:55.000Z","dependencies_parsed_at":"2023-03-11T19:59:20.297Z","dependency_job_id":null,"html_url":"https://github.com/CFETeam/weapp-demo-session","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CFETeam%2Fweapp-demo-session","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CFETeam%2Fweapp-demo-session/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CFETeam%2Fweapp-demo-session/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CFETeam%2Fweapp-demo-session/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CFETeam","download_url":"https://codeload.github.com/CFETeam/weapp-demo-session/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250407703,"owners_count":21425548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T03:00:31.651Z","updated_at":"2025-04-23T09:33:27.184Z","avatar_url":"https://github.com/CFETeam.png","language":"JavaScript","funding_links":[],"categories":["Demo","Uncategorized"],"sub_categories":["Uncategorized"],"readme":"微信小程序示例 - 一笔到底\n=============\n\n[微信小程序](http://mp.weixin.qq.com/wiki?t=resource/res_main\u0026id=mp1474632113_xQVCl\u0026token=\u0026lang=zh_CN)提供了一套在微信上运行小程序的解决方案，有比较完整的框架、组件以及 API，在这个平台上面的想象空间很大。\n\n微信的定位并不是 HTML5，这里很多人都有误解。在一些实现上，并不能想当然地用 HTML5 的思路来思考。比如，微信的请求接口 `wx.request` 并不支持 `cookie` 传递，所以会话层不能使用传统的 Session 方式。\n\n这篇文章分享一个简单的画图应用，使用自己新鲜出炉的小程序会话管理能力来判断并当前用户的身份。\n\n![运行截图](http://easyimage-10066543.file.myqcloud.com/internal/w42ur3da.dw2.jpg)\n\n小程序非常简单，使用 Canvas 绘图后，把序列化的 `actions` 提交给服务器保存。下次加载的时候，再列出用户曾经绘制过的图。\n\n## 部署和运行\n\n拿到了本小程序源码的朋友可以尝试自己运行起来。\n\n### 整体架构\n\n![整体架构](http://easyimage-10066543.file.myqcloud.com/internal/acmql3vd.mql.jpg)\n\n### 1. 准备域名和证书\n\n在微信小程序中，所有的网路请求受到严格限制，不满足条件的域名和协议无法请求，具体包括：\n\n* 只允许和在 MP 中配置好的域名进行通信，如果还没有域名，需要[注册一个](https://www.qcloud.com/product/dm.html?utm_source=jiaocheng\u0026utm_medium=domain2\u0026utm_ca)。\n* 网络请求必须走 HTTPS 协议，所以你还需要为你的域名[申请一个证书](https://console.qcloud.com/ssl?utm_source=jiaocheng\u0026utm_medium=ssl2\u0026utm_campaign=qcloud)。\n\n域名注册好之后，可以登录[微信公众平台](https://mp.weixin.qq.com)配置通信域名了。\n\n![配置通信域名](http://easyimage-10028115.file.myqcloud.com/internal/tjzpgjrz.y5a.jpg)\n\n### 2. 云主机和镜像部署\n\n一笔到底的服务器运行代码和配置已经打包成腾讯云 CVM 镜像，大家可以[直接使用](https://buy.qcloud.com/cvm?marketImgId=371\u0026utm_source=jiaocheng\u0026utm_medium=cvm2\u0026utm_campaign=qcloud)。\n\n\u003e 腾讯云用户可以[免费领取礼包](https://www.qcloud.com/act/event/yingyonghao.html#section-voucher)，体验腾讯云小程序解决方案。\n\n![选择服务市场镜像](http://easyimage-10028115.file.myqcloud.com/internal/p5vbnlfw.yik.jpg)\n\n\u003e 镜像已包含所有小程序的服务器环境与代码，需要体验其它小程序的朋友无需重复部署\n\n### 3. 配置 HTTPS\n\n镜像中已经部署了 nginx，需要在 `/etc/nginx/conf.d` 下修改配置中的域名、证书、私钥。\n\n![证书 Nginx 配置](http://easyimage-10028115.file.myqcloud.com/internal/agfty0fn.gfi.jpg)\n\n配置完成后，即可启动 nginx。\n\n```\nnginx\n```\n\n### 4. 域名解析\n\n我们还需要添加域名记录解析到我们的云服务器上，这样才可以使用域名进行 HTTPS 服务。\n\n在腾讯云注册的域名，可以直接使用[云解析控制台](https://console.qcloud.com/cns/domains?utm_source=jiaocheng\u0026utm_medium=cns\u0026utm_campaign=qcloud)来添加主机记录，直接选择上面购买的 CVM。\n\n![添加域名解析](http://easyimage-10028115.file.myqcloud.com/internal/uw25hdj2.k1u.jpg)\n\n解析生效后，我们在浏览器使用域名就可以进行 HTTPS 访问。\n\n![HTTPS 访问效果图](http://easyimage-10028115.file.myqcloud.com/internal/bxfkmjea.g41.jpg)\n\n### 5. 配置云存储 Redis\n\n会话管理依赖 Redis 进行作为缓存管理，开发者可以选择自行搭建 Redis 服务或者直接购买[云存储 Redis 服务](https://buy.qcloud.com/buy/redis?utm_source=jiaocheng\u0026utm_medium=redis-purchase\u0026utm_campaign=qcloud)。\n\n### 6. 配置云数据库 MongoDB\n\n一笔到底小程序使用 MongoDB 来存储用户绘制的图像路径，要运行小程序开发者需要自行搭建 MongoDB 服务或者直接购买[云数据库 MongoDB](https://buy.qcloud.com/mongodb?utm_source=jiaocheng\u0026utm_medium=mongodb-purchase\u0026utm_campaign=qcloud)。\n\n### 7. 启动一笔到底示例 Node 服务\n\n在镜像的 nginx 配置中（`/etc/nginx/conf.d`），已经把`/applet/session`的请求转发到 `http://127.0.0.1:5757`处理。我们需要把 Node 服务运行起来。Node 代码部署在目录`/data/release/qcloud-applet-session`下。\n\n进入该目录：\n\n```sh\ncd /data/release/qcloud-applet-session\n```\n\n在该目录下有个名为`config.js`的配置文件（如下所示），根据注释将`appId`、`appSecret`、`redisConfig`、`mongoConfig`修改成自己的配置。\n\n```js\nmodule.exports = {\n    port: '5757',\n    ROUTE_BASE_PATH: '/applet',\n\n    // 微信小程序 App ID\n    appId: '',\n\n    // 微信小程序 App Secret\n    appSecret: '',\n\n    // Redis 配置\n    // @see https://www.npmjs.com/package/redis#options-object-properties\n    redisConfig: {\n        host: '',\n        port: '',\n        password: '',\n    },\n\n    // MongoDB 配置\n    // @see https://www.qcloud.com/doc/product/240/3979\n    mongoConfig: {\n        username: '',\n        password: '',\n        host: '',\n        port: '',\n        query: '?authMechanism=MONGODB-CR\u0026authSource=admin',\n        database: 'qcloud-applet-session',\n    },\n};\n```\n\n一笔到底示例使用 pm2 管理 Node 进程，执行以下命令启动 node 服务：\n\n```\npm2 start process.json\n```\n\n## 实现\n\n### 会话层实现\n\n会话层实现包含两个部分：\n\n* 服务器端：[https://github.com/CFETeam/weapp-session](https://github.com/CFETeam/weapp-session)\n* 客户端：[https://github.com/CFETeam/weapp-session-client](https://github.com/CFETeam/weapp-session-client)\n\n我们的 Demo 直接使用这两个仓库，可以快速地拥有会话层的能力。\n\n会话层的实现和传统 Cookie 的实现方式类似，都是在 Header 上使用特殊的字段跟踪。一个请求的完整流程如下：\n\n![请求声明周期](http://easyimage-10066543.file.myqcloud.com/internal/cv1setht.o1x.jpg)\n\n1. 客户端（微信小程序）发起请求 `request`\n2. [weapp-session-client](https://github.com/CFETeam/weapp-session-client) 包装 `request`\n    * 首次请求\n        - 调用 `wx.login()` 和 `wx.getUserInfo()` 接口获得 `code`、`rawData` 和 `signature`\n        - `requset` 的头部带上 `code`、`rawData` 和 `signature`\n        - 保存 `code` 供下次调用\n    * 非首次请求\n        - `request` 的头部带上保存的 `code`\n3. 服务器收到请求 `request`，中间件从头部提取 `code`、`rawData` 和 `signature` 字段\n    * 如果 `code` 为空，跳到第 `4` 步\n    * 如果 `code` 不为空，且 `rawData` 不为空，需要进行签名校验\n        + 使用 `code`，`appid`、`app_secret` 请求微信接口获得 `session_key` 和 `openid`\n            - 如果接口失败，响应 `ERR_SESSION_KEY_EXCHANGE_FAILED`\n        + 使用签名算法通过 `rawData` 和 `session_key` 计算签名 `signature2`\n        + 对比 `signature` 和 `signature2`\n            - 签名一致，解析 `rawData` 为 `wxUserInfo`\n                * 把 `openid` 写入到 `wxUserInfo`\n                * 把 `(code, wxUserInfo)` 缓存到 Redis\n                * 把 `wxUserInfo` 存放在 `request.$wxUserInfo` 里\n                * 跳到第 `4` 步\n            - 签名不一致，响应 `ERR_UNTRUSTED_RAW_DATA`\n    * 如果 `code` 不为空，但 `rawData` 为空，从 Redis 根据 `code` 查询缓存的用户信息\n        - 找到用户信息，存放在 `request.$wxUserInfo` 字段里，跳到第 `4` 步\n        - 没找到用户信息（可能是过期），响应 `ERR_SESSION_EXPIRED`\n4. `request` 被业务处理，可以使用 `request.$wxUserInfo` 来获取用户信息（`request.$wxUserInfo` 可能为空，业务需要自行处理）\n\n## 源代码\n\n可从 Github 获取 [https://github.com/CFETeam/weapp-session](https://github.com/CFETeam/weapp-session)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCFETeam%2Fweapp-demo-session","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCFETeam%2Fweapp-demo-session","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCFETeam%2Fweapp-demo-session/lists"}