开发

  • 开发工具。基本分为三块

(1) Table-item 界面的页数。
(2) Webview 页面在这里实时展示。
(3) Chrome调试工具。

  • 基本文件。

(1)js 脚本文件。监听并处理小程序的生命周期函数、声明全局变量。调用框架提供的APi(应用程序接口)
(2)json 配置文件。是对小程序的全局配置。可以配置背景色,页面组成,导航条样式。 注意:该文件不能添加任何注释。
(3)wxss样式表文件。是小程序的公共样式表。比如我们可以在页面的 class属性直接使用 app.wxsss声明的样式规则。

  1. //app.js
  2. App({
  3. onLaunch: function () {
  4. //调用API从本地缓存中获取数据
  5. var logs = wx.getStorageSync('logs') || []
  6. logs.unshift(Date.now())
  7. wx.setStorageSync('logs', logs)
  8. },
  9. getUserInfo:function(cb){
  10. var that = this;
  11. if(this.globalData.userInfo){
  12. typeof cb == "function" && cb(this.globalData.userInfo)
  13. }else{
  14. //调用登录接口
  15. wx.login({
  16. success: function () {
  17. wx.getUserInfo({
  18. success: function (res) {
  19. that.globalData.userInfo = res.userInfo;
  20. typeof cb == "function" && cb(that.globalData.userInfo)
  21. }
  22. })
  23. }
  24. });
  25. }
  26. },
  27. globalData:{
  28. userInfo:null
  29. }
  30. })
  31. //app.json 是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,
  32. //配置小程序的窗口背景色,配置导航条样式,配置默认标题。注意该文件不可添加任何注释。
  33. //更多可配置项可参考配置详解。
  34. {
  35. "pages":[
  36. "pages/index/index",
  37. "pages/logs/logs"
  38. ],
  39. "window":{
  40. "backgroundTextStyle":"light",
  41. "navigationBarBackgroundColor": "#fff",
  42. "navigationBarTitleText": "WeChat",
  43. "navigationBarTextStyle":"black"
  44. }
  45. }
  46. app.wxss 是整个小程序的公共样式表。我们可以在页面组件的 class 属性上直接使用 app.wxss
  47. //声明的样式规则。
  48. /**app.wxss**/
  49. .container {
  50. height: 100%;
  51. display: flex;
  52. flex-direction: column;
  53. align-items: center;
  54. justify-content: space-between;
  55. padding: 200rpx 0;
  56. box-sizing: border-box;
  57. }
  58. 创建页面
  59. //有两个页面,index 页面和 logs 页面,即欢迎页和小程序启动日志的展示页,他们都在 pages 目录下。
  60. //微信小程序中的每一个页面的【路径+页面名】都需要写在 app.json 的 pages 中,且
  61. //pages 中的第一个页面是小程序的首页。
  62. 每一个小程序页面是由同路径下同名的四个不同后缀文件的组成,如:index.jsindex.wxml
  63. //index.wxss、index.json。.js后缀的文件是脚本文件,.json后缀的文件是配置文件,
  64. //.wxss后缀的是样式表文件,.wxml后缀的文件是页面结构文件。
  65. index.wxml 是页面的结构文件:
  66. <!--index.wxml-->
  67. <view class="container">
  68. <view bindtap="bindViewTap" class="userinfo">
  69. <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image>
  70. <text class="userinfo-nickname">{{userInfo.nickName}}</text>
  71. </view>
  72. <view class="usermotto">
  73. <text class="user-motto">{{motto}}</text>
  74. </view>
  75. </view>
  76. //index.js 是页面的脚本文件,在这个文件中我们可以监听并处理页面的生命周期函数、获取小程序实例,
  77. //声明并处理数据,响应页面交互事件等。
  78. //index.js
  79. //获取应用实例
  80. var app = getApp()
  81. Page({
  82. data: {
  83. motto: 'Hello World',
  84. userInfo: {}
  85. },
  86. //事件处理函数
  87. bindViewTap: function() {
  88. wx.navigateTo({
  89. url: '../logs/logs'
  90. })
  91. },
  92. onLoad: function () {
  93. console.log('onLoad')
  94. var that = this
  95. //调用应用实例的方法获取全局数据
  96. app.getUserInfo(function(userInfo){
  97. //更新数据
  98. that.setData({
  99. userInfo:userInfo
  100. })
  101. })
  102. }
  103. })
  104. //index.wxss 是页面的样式表:
  105. /**index.wxss**/
  106. .userinfo {
  107. display: flex;
  108. flex-direction: column;
  109. align-items: center;
  110. }
  111. .userinfo-avatar {
  112. width: 128rpx;
  113. height: 128rpx;
  114. margin: 20rpx;
  115. border-radius: 50%;
  116. }
  117. .userinfo-nickname {
  118. color: #aaa;
  119. }
  120. .usermotto {
  121. margin-top: 200px;
  122. }

选择微信小程序模式,需要自行下载并打开微信开发者工具,然后选择项目根目录进行预览。
微信小程序编译预览及打包(去掉 —watch 将不会监听文件修改,并会对代码进行压缩打包)

  1. # npm script
  2. $ npm run dev:weapp
  3. $ npm run build:weapp
  4. # 仅限全局安装
  5. $ taro build --type weapp --watch
  6. $ taro build --type weapp
  7. # npx 用户也可以使用
  8. $ npx taro build --type weapp --watch
  9. $ npx taro build --type weapp

架构

session+cookie
  • Session和Cookie都是由服务器生成的
  • Session和Cookie都是键值对形式保存,主要用于存储特定的一些状态值。
  • Session保存在服务器Cookie保存在客户端。通常,Session的ID会以Cookie的形式返回给客户端的。
  • Session和Cookie都是有生命周期的。Cookie的生命周期受到Cookie自身的有效期和客户端的影响,一般来说,浏览器(客户端)是会自动将存活的Cookie封装在请求头里面,向服务器发送。如果Cookie有效期过期或客户端清理了Cookie,则发送的请求中就没有Cookie值;Session的生命周期受到Session自身的有效期和客户端是否关闭的影响。SessionID虽然是已Cookie的形式返回给客户端,但是它是不受客户的Cookie容器的管理,而是和客户端进程有关,即客户端进程不关闭,一般Session在客户端就不会失效。
  • Session和Cookie都是有作用域
    • cookie

如果是POST方式访问,从提交过来的数据中验证用户是否登录成功,登录成功便将用户名设置到cookie,并且返回给客户端,进入欢迎页。
如果是GET方式访问,则从访问的cookie中获取用户信息,如果从cookie中能获取到用户名,则认为用户已登录,返回欢迎页

  • session

如果是POST方式访问,从提交过来的数据中验证用户是否登录成功,登录成功便将用户名设置到Session中,并且返回给客户端,进入欢迎页。
如果是GET方式访问,则从访问的Session中获取用户信息,如果从Session中能获取到用户名,则认为用户已登录,返回欢迎页
cookie比session更容易受攻击

image.png

1、在客户端获取当前登录微信用户的登录凭证(code)
我们可以使用wx.login获得一个微信用户登录的临时凭证,这个操作可以在App.js中执行,也可以在页面文件中执行,根据业务需求来选择。

  1. App({
  2. onLaunch: function() {
  3. wx.login({
  4. success: function(res) {
  5. var code = res.code;
  6. if (code) {
  7. console.log('获取用户登录凭证:' + code);
  8. } else {
  9. console.log('获取用户登录态失败:' + res.errMsg);
  10. }
  11. }
  12. });
  13. }
  14. })

2、将临时code发送我们的服务器,在服务器端向微信服务器换取该用户的唯一标识(openid)和会话密钥(session_key)

  1. App({
  2. onLaunch: function() {
  3. wx.login({
  4. success: function(res) {
  5. var code = res.code;
  6. if (code) {
  7. console.log('获取用户登录凭证:' + code);
  8. // --------- 发送凭证 ------------------
  9. wx.request({
  10. url: 'https://www.shanzhonglei.com/wx/login',
  11. data: { code: code }
  12. })
  13. // ------------------------------------
  14. } else {
  15. console.log('获取用户登录态失败:' + res.errMsg);
  16. }
  17. }
  18. });
  19. }
  20. })

在我们的服务器后台,需要使用这个code来换取该用户的唯一标识(openid)和会话密钥(session_key)。这个openid是用户的唯一标识,是微信用户在小程序生态中唯一的标识。值得注意的是:
会话密钥session_key 是对用户数据进行加密签名的密钥。
为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
临时登录凭证code只能使用一次。
临时登录凭证校验接口是一个HTTPS接口。
接口地址:
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

后端代码构建:

  1. const Koa = require('koa');
  2. const Router = require('koa-router');
  3. const bodyParser = require('koa-bodyparser');
  4. const request = require('request');
  5. const app = new Koa();
  6. const router = new Router();
  7. app.use(bodyParser());
  8. // 配置文件
  9. const minproSetting = require('./config');
  10. // 路由处理
  11. router.get('/', (ctx, next) => {
  12. // 获取code
  13. let code = ctx.query.code;
  14. let queryData = ctx.query;
  15. debugger;
  16. let url = `https://api.weixin.qq.com/sns/jscode2session?appid=${minproSetting.appid}&
  17. secret=${minproSetting.appsecret}&js_code=${code}&grant_type=authorization_code`
  18. request({ method: 'GET', url: url, json: true }, function (error, response, body) {
  19. // 验证获取的数据
  20. const exporesIn = body.expores_in;
  21. const openid = body.openid;
  22. const session_key = body.session_key;
  23. })
  24. });
  25. app
  26. .use(router.routes())
  27. .use(router.allowedMethods());
  28. app.listen(8888);

请不要直接使用这些信息作为小程序的用户标识和session标识回传到小程序客户端。在服务器端应该把openid和session_key进行封装成sessionid,把sessionid派发到小程序客户端作为session来使用的。在服务端做session机制,我们一般使用键值对存储工具来做,比如redis,为了安全,应该设置一个超时的时间。
3、在客户端保存sessionid
在开发web应用的时候,我们通常是将sessionid存在cookie中,但是小程序是没有cookie机制的,所以不能采用cookie了,但是小程序有本地的storage,我们可以使用storage来保存sessionid,之后调用那些需要登录才有权限访问的后台服务时,就把sessionid从本地读取出来,放在请求中发至后台。后台服务需要验证sessionid的有效性,我们可以使用自定义中间件来验证。
在小程序中每次调用后台业务API的时候,先使用wx.checkSession()来检查会话是否过期,如果已过期,则重新调用建立会话的代码流程,然后再调用目标业务API;如果未过期,则直接调用业务API。
如果系统对数据安全要求不高的话,也可以不采用session机制。第一次登录生成sessionid后返回给用户并存到storage中,以后每次后台请求都读取storage,如果读取不到storage,则重新走以一遍登录流程生成sessionid

完整过程

  1. 1、在客户端获取当前登录微信用户的登录凭证(code)
  2. 我们可以使用wx.login获得一个微信用户登录的临时凭证,这个操作可以在App.js中执行,也可以在页面文件中执行,根据业务需求来选择。
  3. App({
  4. onLaunch: function() {
  5. wx.login({
  6. success: function(res) {
  7. var code = res.code;
  8. if (code) {
  9. console.log('获取用户登录凭证:' + code);
  10. } else {
  11. console.log('获取用户登录态失败:' + res.errMsg);
  12. }
  13. }
  14. });
  15. }
  16. })
  17. 2、将临时code发送我们的服务器,在服务器端向微信服务器换取该用户的唯一标识(openid)和会话密钥(session_key)
  18. App({
  19. onLaunch: function() {
  20. wx.login({
  21. success: function(res) {
  22. var code = res.code;
  23. if (code) {
  24. console.log('获取用户登录凭证:' + code);
  25. // --------- 发送凭证 ------------------
  26. wx.request({
  27. url: 'https://www.shanzhonglei.com/wx/login',
  28. data: { code: code }
  29. })
  30. // ------------------------------------
  31. } else {
  32. console.log('获取用户登录态失败:' + res.errMsg);
  33. }
  34. }
  35. });
  36. }
  37. })
  38. 在我们的服务器后台,需要使用这个code来换取该用户的唯一标识(openid)和会话密钥(session_key)。这个openid是用户的唯一标识,是微信用户在小程序生态中唯一的标识。值得注意的是:
  39. 会话密钥session_key 是对用户数据进行加密签名的密钥。
  40. 为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。
  41. 临时登录凭证code只能使用一次。
  42. 临时登录凭证校验接口是一个HTTPS接口。
  43. 接口地址:
  44. https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
  45. 后端代码构建:
  46. const Koa = require('koa');
  47. const Router = require('koa-router');
  48. const bodyParser = require('koa-bodyparser');
  49. const request = require('request');
  50. const app = new Koa();
  51. const router = new Router();
  52. app.use(bodyParser());
  53. // 配置文件
  54. const minproSetting = require('./config');
  55. // 路由处理
  56. router.get('/', (ctx, next) => {
  57. // 获取code
  58. let code = ctx.query.code;
  59. let queryData = ctx.query;
  60. debugger;
  61. let url = `https://api.weixin.qq.com/sns/jscode2session?appid=${minproSetting.appid}&
  62. secret=${minproSetting.appsecret}&js_code=${code}&grant_type=authorization_code`
  63. request({ method: 'GET', url: url, json: true }, function (error, response, body) {
  64. // 验证获取的数据
  65. const exporesIn = body.expores_in;
  66. const openid = body.openid;
  67. const session_key = body.session_key;
  68. })
  69. });
  70. app
  71. .use(router.routes())
  72. .use(router.allowedMethods());
  73. app.listen(8888);
  74. 请不要直接使用这些信息作为小程序的用户标识和session标识回传到小程序客户端。在服务器端应该把openidsession_key进行封装成sessionid,把sessionid派发到小程序客户端作为session来使用的。在服务端做session机制,我们一般使用键值对存储工具来做,比如redis,为了安全,应该设置一个超时的时间。
  75. 3、在客户端保存sessionid
  76. 在开发web应用的时候,我们通常是将sessionid存在cookie中,但是小程序是没有cookie机制的,所以不能采用cookie了,但是小程序有本地的storage,我们可以使用storage来保存sessionid,之后调用那些需要登录才有权限访问的后台服务时,就把sessionid从本地读取出来,放在请求中发至后台。后台服务需要验证sessionid的有效性,我们可以使用自定义中间件来验证。
  77. 在小程序中每次调用后台业务API的时候,先使用wx.checkSession()来检查会话是否过期,如果已过期,则重新调用建立会话的代码流程,然后再调用目标业务API;如果未过期,则直接调用业务API
  78. 如果系统对数据安全要求不高的话,也可以不采用session机制。第一次登录生成sessionid后返回给用户并存到storage中,以后每次后台请求都读取storage,如果读取不到storage,则重新走以一遍登录流程生成sessionid