微信小程序踩坑指南

最近因为公司业务一直在做微信小程序的项目,趁此机会将最近踩过的一些坑总结记录下。

微信小程序登陆相关

  • 前端调用wx.login(),获取临时登录凭证 code
  • 通过wx.request()将code发给服务器(需要后端创建接口接收code)
  • 后端进行登录凭证校验,入参为(appid,secret,js_code,grant_type)

appid 小程序唯一标识 secret 小程序的 app secret js_code 登录获取的 code grant_type 填写为 authorization_code

  • 登陆凭证校验通过,从微信服务器换取openid和session_key

openid 用户唯一标识 session_key 会话密钥

openid 是用户唯一标识,但不建议直接用做后端服务器的各用户标示符。 session_key 是针对用户数据进行加密签名的密匙。session_key 在文件校验,获取用户具体信息时均需使用

一般为了安全起见,这两个数据都不会发往客户端。

  • 后端将session_key处理之后,返回前端一个处理后的一个字符串作为用户的登陆标识,一般以token的形式。(自定义登陆态与openid session_key相关)
  • 前端接收到token,储存到localStorage中,每次向服务器请求数据的时候带上,作为服务器识别用户的凭证。
  • 后续用户进入小程序时,首先调用 wx.checkSession() 检测登陆态,如果失败,重新发起登陆流程。
//app.js
const NOLOGINCODE = 1000003  //未登录
const SUCCESS = 1000001 //成功
App({
  onLaunch: function () {
    var loginFlag = wx.getStorageSync('sessionId');
    var that = this;
    if (loginFlag) {
      // 检查 session_key 是否过期
      wx.checkSession({
        // session_key 有效(未过期)
        success: function () {
          var userInfo = wx.getStorageSync('wxUserInfo')
          if (userInfo) {
            that.globalData.hasUserInfo = true
          }
        },// session_key 过期
        fail: function () {
          // session_key过期,重新登录
          that.doLogin();
        }
      });
    } else {
      // 无skey,作为首次登录
      this.doLogin();
    }
  },doLogin() {
    this.log().then(res => {
      this.$post('/auth',{ code: res.code,},false).then(data => {
        wx.setStorageSync('sessionId',data.sessionId);
      })
    })
  },/**
   *微信登录 获取code值,并将code传递给服务器
   * @returns
   */
  log() {
    return new Promise(resolve => {
      wx.login({
        success(res) {
          if (res.errMsg === "login:ok") {
            resolve(res)
          } else {
            wx.showToast({
              title: '微信登录失败',icon: 'none',duration: 1200
            })
          }
        },fail() {
          wx.showToast({
            title: '微信登录接口调用失败',duration: 1200
          })
        }
      })
    })
  },globalData: {
    baseurl: 'https://www.fake.shop'
  }
})
复制代码

网络请求封装

微信小程序中网络请求的api是wx.request(),但是这个请求是个异步回调的形式,每次发请求都要写好长一串,而且如果是嵌套的发请求,就会发现代码写的及其臃肿,所以将其 Promisefy是及其有必要的。 代码如下:

 $get(url,data = {},needToken = true) {
    let SUCCESS = 200
    var that = this
    needToken ? (data.token = wx.getStorageSync('ToKen')) : ''
    return new Promise((resolve,reject) => {
      wx.request({
        url: that.globalData.baseurl + url,method: "GET",header: {
          'content-type': 'application/json'
        },data: data,success(e) {
          if (e.data.code == SUCCESS) {
            resolve(e.data)
            return
          }

        },fail(e) {
          wx.showModal({
            title: '提示',content: '请求失败',showCancel: false
          })
          reject(e)
        }
      })
    })
  },$post(url,needToken = true) {
    let that = this
    let SUCCESS = 200
    let TimeOut = 1000
    var that = this
    needToken ? (data.token = wx.getStorageSync('ToKen')) : ''
    return new Promise((resolve,method: "POST",//此处可以根据接口文档设置header头
        // header: { 
        //   'content-type': 'application/x-www-form-urlencoded'
        // },
        data: data,success(e) {
          if (e.statusCode == SUCCESS) {
            if (e.data.code == SUCCESS) {
              resolve(e.data)
            }
            else {
              reject(e)
              wx.showModal({
                title: '提示',content: e.data.msg,showCancel: false,success: function (res) {
                  if (res.confirm) {
                    if (e.data.code == TimeOut) { //根据实际业务返回的code码判断是否过期
                      // 登录过期
                      that.doLogin();
                    }
                  }
                }
              })
            }
          } else {
            wx.showModal({
              title: '提示',content: e.data.error,showCancel: false
            })
            reject(e)
          }
        },fail(e) {
          console.log(e)
          wx.showModal({
            title: '提示',showCancel: false
          })
          reject(e)
        },complete(e) {
        }
      })

    })
  },复制代码

微信公共号支付(微信浏览器)

虽然是写小程序踩坑指南,但是在微信内的H5页面支付和小程序内掉起支付还是有相似之处的,顺便记录一下。

应用场景

  • 已有 H5 商城网站,用户通过消息或扫描二维码在微信内打开网页时,可以调用微信支付完成下单购买的流程。
准备

UnionID:为了识别用户,每个用户针对每个公众号会产生一个安全的 OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的 OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个 UnionID 网页授权: 一些复杂的业务场景下,需要以网页的形式提供服务,通过网页授权可以获取用户的openid(注:获取用户的 OpenID 是无需用户同意的,获取用户的基本信息则需用户同意) 微信 JS-SDK:是开发者在网页上通过 JavaScript 代码使用微信原生功能的工具包,开发者可以使用它在网页上录制和播放微信语音、监听微信分享上传手机本地图片、拍照等许多能力。

业务流程时序图

主要流程
  • 网页内引入jssdk,主要有两种
  • 网页授权
    • 我的理解就是网页授权主要是为了使在微信浏览器里面打开的第三方网页,可以跟微信公共号以及用户的微信相关联的操作,最终获取用户在该公共号下的openid.
    • 网站应用微信登录是基于 OAuth2.0 协议标准构建的微信 OAuth2.0 授权登录系统。获取 openid 分为两步
      • 前端通过跳转网址获取 code,然后将code发送给后端
      • 后端然后根据 code 获取 openid。

code的获取

URLEncoder.encode(payUrl)是非常有必要的 state参数: 用于保持请求和回调的状态,授权请求后原样带回给第三方。该参数可用于防止 csrf 攻击(跨站请求伪造攻击),建议第三方带上该参数,可设置为简单的随机数加 session 进行校验 后端获取openid的原因: 因为我是前端,不想搞这个(开玩笑的

相关文章

开发微信小程序的用户授权登录功能
小程序开发页面如何实现跳转?
浅谈小程序开发中蓝牙连接错误分析及解决方法
什么是小程序?它有哪些功能?
如何配置小程序开发项目结构?(教程)
怎么把自己的店加入小程序