手机版

小程序填坑技巧的网络请求转化

时间:2021-12-10 来源:互联网 编辑:宝哥软件园 浏览:

内测的时候小程序已经开始玩了,但是刚开始的时候觉得这个sx的事情好尴尬。网络请求不是返回承诺,而是回调。当传递值时,我不能在方法中写入值,而只能使用数据集。在这个全面的组件化环境中,我不支持组件化。

其实一开始主要是写作的习惯。既然不做小程序开发,就随你的态度去吧。然而,有意想不到的事件。最近因为业务需要,要做与小程序相关的开发,所以很固执,也很坚决,实在受不了。果断的把不愉快的地方变成我喜欢走的路。其中我也遇到了一些其他的漏洞,慢慢一个一个的填,记录下来,编成文章。

网络请求

网络请求小程序提供wx.request这是我最想吐槽的点。仔细看看api。这不是那美元吗?n年前的ajax产品?太旧了。

//官方示例wx.request ({url:' test.php ',//仅为示例,并非真实接口地址data: {x: ' ',y: ''},Header : { ' content-type ' : ' application/JSON '//default value },succe 3360 function(RES){ console . log(RES . data)})现在只有一个请求,感觉写起来很长。如果一个页面需要多个请求,如果仍然需要请求的顺序,该怎么办?各种筑巢都是又臭又长。如果请求是必需的,则在所有请求完成后将显示界面。

这时,我弱弱地看了一下JS版小程序的支持者,瓦耶,他在支持ES6方面比较尽责。也就是说,我们可以改成Promise。有可能。接下来,让我们看看我是如何改造它的。

/* utils/api.js自定义网络请求*/const base URL=' https://your api . com '/自己的后台API地址const http=({ url=' ',params={},other }={ })={ wx . show loading({ title : ' loading . '})Lettime=date . now(). console . log(` start : $ { time } `)返回新的承诺((resolve,reject)={ wx . request({ URL : GetURl(URL),data: params,header: getHeader(),其他,complete :(RES)={ wx . hide loading()console . log(`耗时: $ { date . now()-time } `)if(RES . status code=200 RES . status code 300){ resolve(RES . data)} else { reject(RES)} } } } })} } const getUrl=URL={ if(URL . indexof(' :/')=-1){ URL=baseURL URL } return URL } getHeader const get (url,params={}) { return http({ url,params }) },post(url,params={}) { return http({ url,params,Method :' post'}),put (URL,params={}) {return http ({URL,params,method:' put'})},//这里不能用delete,delete是关键字字段myDelete(url,Params={}) {return http ({URL,params }) 写一个简单的例子。

常量ap

i = require('../../utils/api.js')// 单个请求api.get('list').then(res => { console.log(res)}).catch(e => { console.log(e)})// 一个页面多个请求Promise.all([ api.get('list'), api.get(`detail/${id}`)]).then(result => { console.log(result)}).catch(e => { console.log(e)})

如果习惯了 fetch 以及 axios 的朋友应该都会比较喜欢这种写法。 在做网络请求的时候还遇到一个问题,登录授权的问题。

登录问题

做一个应用,肯定避免不了登录操作。用户的个人信息啊,相关的收藏列表等功能都需要用户登录之后才能操作。一般我们使用token做标识。然后又会涉及到token不存在,用户第一次登录,token过期后,重新登录等问题。比较常规的操作是直接跳转到登录页面。

然后坑就出现了,小程序并没有登录界面,使用的是wx.login。wx.login会获取到一个 code,拿着该 code 去请求我们的后台会最后返回一个token到小程序这边,保存这个值为token每次请求的时候带上这个值。(详情可以查看小程序登录。)

然而仅仅这样就够了吗? 很显然并不是。一般还需要把用户的信息带上比如用户微信昵称,微信头像等,这时候就需要使用wx.getUserInfo,这里涉及到一个用户授权的问题,留一个坑接下来再解决。带上用户信息就够了嘛? too young too simple!我们的项目不可能只有小程序,相应的微信公众平台可能还有相应的App,我们需要把账号系统打通,让用户在我们的项目中的账户是同一个。这就需要用到微信开放平台提供的UnionID。

ps.基于小程序在微信中的易传播性, 为了鼓励用户去传播分享一般还会提供邀请奖励机制。但是微信这边又会对诱导分享进行和谐处理。视情况慎用。(本文会在例子上加上该功能)

看到这,是不是觉得头都大了,就一个小小的登录功能坑这么多。 年轻的我瑟瑟发抖~~~。慢慢开始填吧。先上登录代码

/* utils/api.js  自定义网络请求 */...function login() {  return new Promise((resolve, reject) => {    // 先调用 wx.login 获取到 code    wx.login({      success: res => {        // 再调用 wx.getUserInfo 获取到用户的一些信息 (一些基本信息,以及生成UnionID 所用到的信息 比如 rawData, signature, encryptedData, iv)        wx.getUserInfo({          // 若获取不到用户信息 (最大可能是用户授权不允许,也有可能是网络请求失败,但该情况很少)          fail: (e) => {            reject(e)          },          success: ({ rawData, signature, encryptedData, iv }) => {            let param = {              code: res.code,              rawData,              signature,              encryptedData,              iv            }            // 若有邀请ID            try {              let invite = wx.getStorageSync('invite')              if (invite) {                param.invite = invite              }            } catch (e) {            }            // 登录操作            http({              url: 'login',              params: param,              method: 'post'            }).then(res => {              // 该为我们后端的逻辑 若code > 0为登录成功,其他情况皆为异常 (视自身情况而定)              if (res.code > 0) {                // 保存用户信息                 wx.setStorage({                  key: 'userinfo',                  data: res.data                })                wx.setStorage({                  key: "token",                  data: res.message,                  success: () => {                    resolve(res)                  }                })              } else {                reject(res)              }            }).catch(error => reject(error))          }        })      }    })  })}...

授权问题

根据上面的代码,可以很清楚的看到,若用户在登录的时候不允许小程序获取他的用户信息之后才能继续。若用户在这个时候点拒绝了呢, 会怎么样? 一片空白!~~ What’s the fuck! 怎么什么都没有!垃圾破小程序~~ 冷静点的用户也会百脸懵逼状。我是谁?我该怎么办? 也许你会觉得,用户点允许就好了啊,怎么会这么笨,这种用户肯定不会多之类的话。我在我们小程序中加了统计大约有20%的用户点了拒绝, 如果后续我们没有做任何引导的话,这 20% 的用户就会永远失去。这个后果我们完全不能接受。

经过我们的小组研究与讨论,给出了一下的一套方案。

小程序的填坑小技巧之网络请求改造(图1)

具体代码可以如下表示,用到了wx.openSetting来跳转到设置授权界面。

/* index.js */// 若有用户信息存在则继续Page({  onLoad () {    wx.getStorage({      key: 'userinfo',      success: (res) => {        this.setUserinfo(res)      },      fail: (res) => {        api.login().then((res) => {          this.setUserinfo(res)        }).catch(e => {          if (e.errMsg && e.errMsg === 'getUserInfo:fail auth deny') {            this.setData({              isauth: false            })          }        })      }    })  },  toSetting() {    wx.openSetting({      success: (res) => {        this.setData({          isauth: res.authSetting['scope.userInfo']        })        if (res.authSetting['scope.userInfo']) {          api.login().then((res) => {            this.setUserinfo(res)          })        }      }    })  }})// setUserinfo 就是对用户信息做一下处理 不具体展开了/* index.wxml */<view class="unauth" wx:if="{{!isauth}}">   <image class="unauth-img" src="../../images/auth.png"></image>   <text class="unauth-text">检查到您没打开授权</text>  <button class="color-button unauth-button" bindtap="toSetting">去设置</button></view><view class="container" wx:else>...</view>

token 失效问题

登录获取到的 token 是有时效的,失效过了会怎么样 ? 如果后台小伙伴严格按照 REST API 规范设计接口 API 的话,他会给我们返回一个错了 http code 为 401。(常见的Http Code以及相关代码的意义本文就不做展开了,不了解的小伙伴可以自行 google 百度一下。)401 之后我们就需要对该Code进行相应的处理。可以如下这么写

api.get('list').then(res => {  /* do something */}).catch(e => {  if (res.statusCode === 401) {    api.login().then(() => {      api.get('list').then(res => {        /* do something */      })    })  }})

看起来没什么问题,也完成需求了。但是会发现这有很大的问题。

  1. 每个请求都需要加 401 的判断,项目大起来 这块的代码量是非常恐怖的
  2. 接口返回的之后的处理/* do something */也是重复的 (当然把这整块内容都提取出来,这里就调用也行。不过还是想把调用这边也省略掉 ^-^ )

屡一下我们要实现的目标。

  1. 需要在每个请求后面都加一个 401 的判断
  2. 若未授权 则进行重新登录
  3. 重新登录之后继续前一个请求
  4. 将该请求结果返回到第一个请求的结果里去(实现无感知重新登录获取信息)

这个体现出把自己封装一个网络请求的好处, 我们可以直接改写 api.js 中的 http 方法里对 error 的处理就好。上代码:

const http = ({ url = '', params = {}, ...other} = {}) => {  wx.showLoading({    title: '加载中...'  })  let time = Date.now()  console.log(`开始:${time}`)  return new Promise((resolve, reject) => {    wx.request({      url: getUrl(url),      data: params,      header: getHeader(),      ...other,      complete: (res) => {        wx.hideLoading()        console.log(`耗时:${Date.now() - time}`)        if (res.statusCode >= 200 && res.statusCode < 300) {          resolve(res.data)        } else if (res.statusCode === 401) {          // 401 为鉴权失败 很大可能是token过期          // 重新登录 并且重复请求          login().then(res => {            http({ url, params, ...other }).then(res => {              resolve(res)            })          })        } else {          reject(res)        }      }    })  })}

小结

网络请求这块,算目前开发项目中必不可少的一块。但是例如 小程序,vue, react, weex 等其实都有一套自己的或者自己推荐的一套API以及相应的写法。没一个都按照他推荐的来写,其实挺蛋疼的,用着很不爽。把他们的API封装一下,暴露出来统一的API, 给自己用或者尤其是给自己团队的小伙伴用就比较方便,少了很多重复学习成本,并且因为统一的API带来的统一的格式也是很大的一个好处。

说到小程序要弄清楚的东西不少,有些坑我还在摸索怎么处理。比如小程序的组件化,全局变量的使用(什么值可以放在app.js里),html标签的转换等,后续弄透了我会再出来献丑的。

版权声明:小程序填坑技巧的网络请求转化是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。