上一章我们主要学习了,小程序有代表性的组件,
组件是开发小程序项目的砖瓦基石,学习组件是学习小程序开发必不可少的一部分。
如果说组件是小程序开发的砖瓦基石,那么接口就好比是水泥,
接口可以将组件,将前端UI与后端的数据串联起来,最终组成我们想要的软件功能。
从这节课开始我们主要学习网络接口,wx.request,并且基于这个基础的接口,我们尝试封装出一个自动整合用户登录的工具类方法。
因为在前端的接口请求中,有些是不需要登录鉴权的,有些却是需要用户预先登录的,
如果用户在没有登录的情况下,请求了某个需要登录的接口,并且可以自动完成登录,自动继续接口的请求,
这样将可以大大的方便前端开发,让我们的逻辑以及代码变的更加地简洁。
那么怎么实现这个功能呢,从这节课开始,我们就看可以看具体的实现过程。
RequestTask
基础库 1.4.0 开始支持,低版本需做兼容处理。
它将返回一个网络请求任务对象
方法
RequestTask.abort() 中断请求任务
可以在数据没有返回之前,就取消网络请求
RequestTask.onHeadersReceived(function callback) 监听 HTTP Response Header 事件。会比请求完成事件更早
它触发的实际比请求完成的事件还要早一些,可以让我们在还没有收到数据的时候,只要拿到了HTTP的状态码,就可以决定是否要终端这个请求了
RequestTask.offHeadersReceived(function callback) 取消监听 HTTP Response Header 事件
但是在实际操作的时候,我们从方法的回调函数中,并不能拿到HTTP状态码,无法监听到类似于401没有鉴权、302服务器发生跳转等等这样的HTTP状态码,但可以拿到像Content-Length字段,进行判断
在开发中有一个这样的场景,这个方法可能是有用的,
假设我们有多个服务器IP,连接任何一个都可以,
但是由于用户他离每个服务器的网络距离它是不一样的,对于每个服务器的链接速度也是不一样的,
在这种情况下,我们就可以让三个设置更多的瞄向不同服务器的网络连接请求同时发出,只要有一个成功连接了,
我们就把其他请求全部abort掉。
在我们之前实现小程序内,一键登录的时候,曾经使用过这个接口,
// 使用checkSession
login(e) {
console.log(e);
let {
userInfo,
encryptedData,
iv
} = e.detail
console.log('userInfo', userInfo);
const requestLoginApi = (code) => {
wx.request({
url: 'http://localhost:3000/user/wexin-login2',
method: 'POST',
header: {
'content-type': 'application/json'
},
data: {
code: code,
userInfo,
encryptedData,
iv
},
success(res) {
console.log('请求成功', res.data)
let token = res.data.data.authorizationToken
wx.setStorageSync('token', token)
onUserLogin(token)
console.log('authorization', token)
},
fail(err) {
console.log('请求异常', err)
}
})
}
const onUserLogin = (token) => {
getApp().globalData.token = token
wx.showToast({
title: '登陆成功了',
})
}
wx.checkSession({
success() {
console.log('在登陆中');
let token = wx.getStorageSync('token')
if (token) onUserLogin(token)
},
fail() {
wx.login({
success(res0) {
if (res0.code) {
requestLoginApi(res0.code)
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
}
})
}
在login函数,我们主要调用了三个接口,
使用 wx.checkSession 这个接口,检查当前的微信登录状态是否还有效,
使用 wx.login ,拉取当前用于微信auth登录鉴权的code
使用 wx.request ,请求了我们自己创建的后台登录接口
从上面可以看出来,所有小程序的接口,它基本上都有这样的两个特征,
第一个特征,参数是一个对象,可以让参数的定义与添加,更加的自由
第二个特征,都有success、fail、complete三个回调属性
这种方式可以方便开发者记忆。
其中success、fail、complete这三个回调属性,都是function类型
它们在逻辑层回调的时候,有不同的参数
success的参数是一个回调成功对象,它是在请求调用成功时返回的
fail,是一个失败对象,在调用出现异常的时候返回
complete,是无论调用成功还是失败,都会调用,甚至是在使用abort方法,取消调用的时候也会返回。
complete参数要么是成功对象,要么是失败对象,要么是一个取消对象。
{errMsg:"request:ok"...}
{errMsg:"request:fail"...}
{errMsg:"request:fail abort"...}
无论调用情况如何,在回调函数中会回传的实际参数对象中,都有一个errMsg的字符串属性
这个属性在成功的时候,它等于接口名加:ok
它失败的时候,它等于接口名加:fail,这样一个格式
在取消的时候,它等于接口名加:fail abort
通过这个字段我们可以在complete的回调函数里面,简单的判断这个接口调用是否是成功的
接下来我们从本课程的源码中,查看一下wx.request接口,如何使用,如何调用,以及在请求发出去以后,我们如何中断请求。
2.2 如何使用,如何调用
<view class="page-head">
<text class="page-head__title">wx.requesttext>
<text class="page-head__desc">网络请求text>
view>
<view class="page-section">
<text class="page-section__title">3.1 接口调用及返回text>
<view class="btn-area">
<button bindtap="startOneRequest" type="primary">发起button>
view>
view>
startOneRequest(e){
wx.request({
url:"http://localhost:3000",
success(res){
if(res.errMsg === "request:ok") console.log("success-res",res);
},
fail(err){
if(err.errMsg === "request:fail") console.log("err",err);
},
complete(res){
console.log("complete-res",res);
}
})
},
startOneRequest(e){
wx.request({
url:"http://localhost:30001",
success(res){
if(res.errMsg === "request:ok") console.log("success-res",res);
},
fail(err){
// if(err.errMsg === "request:fail" ) console.log("err",err);
// 用 === 会有坑,可能返回的时候fail后面加的有空格,所以用indexOf或者正则匹配
// 方法1:
if(err.errMsg.indexOf("request:fail") > -1 ) console.log("err",err);
// 方法2:
if(/^request:fail/i.test(err.errMsg)) console.log("err",err); // ^以什么为开头 i不区分大小写 :冒号不用转义,可以直接使用
},
complete(res){
console.log("complete-res",res);
}
});
wx.request({
url:"http://localhost:3000/hi",
success(res){
if(res.errMsg === "request:ok") console.log("hi-success-res",res);
},
fail(err){
if(/^request:fail/i.test(err.errMsg)) console.log("hi-err",err);
},
complete(res){
console.log("hi-complete-res",res);
}
});
wx.request({
url:"http://localhost:3000/user/home",
success(res){
if(res.errMsg === "request:ok") console.log("home-success-res",res);
},
fail(err){
if(/^request:fail/i.test(err.errMsg)) console.log("home-err",err);
},
complete(res){
console.log("home-complete-res",res);
}
});
},
2.3 如何中断请求
let reqTask = wx.request({
url:"http://localhost:3000/user/home",
success(res){
if(res.errMsg === "request:ok") console.log("home-success-res",res);
},
fail(err){
if(/^request:fail/i.test(err.errMsg)) console.log("home-err",err);
},
complete(res){
console.log("home-complete-res",res);
}
});
reqTask.abort();
2.4 中断请求的应用
在正常开发过程中,我们并不会发出一个请求以后,直接就把这个请求中断掉,那么我们的请求在这种情况下也就没有意义了。
多数情况下我们是在发出请求后,根据我们的逻辑去判断的,所以我们有时候需要去监听我们请求的一种状态,
RequestTask,它本身提供了两个函数,让我们去监听它的状态,
onHeadersReceived 添加监听
offHeadersReceived 移除监听
// 方式一:可以采用
const reqTaskOnHeadersReceived = (headers)=>{
console.log("headers",headers);
// 最好是拿到这个状态之后,移除监听 移除方式一 + 箭头函数
reqTask.offHeadersReceived(reqTaskOnHeadersReceived);
}
reqTask.onHeadersReceived(reqTaskOnHeadersReceived)
// --------------------------------------------------------------
// 方式二:严格模式不采用
const reqTaskOnHeadersReceived = function(headers){
console.log("headers",headers);
// 移除监听 移除方式二 + function函数
// arguments.callee 指的是函数自身 reqTaskOnHeadersReceived
reqTask.offHeadersReceived(arguments.callee);
// reqTask.offHeadersReceived(reqTaskOnHeadersReceived);
}
reqTask.onHeadersReceived(reqTaskOnHeadersReceived)
// --------------------------------------------------------------
// 综上修改 如下
// 匿名函数 + 方式二 : 严格模式不采用
reqTask.onHeadersReceived(function(headers){
console.log("headers",headers);
// 移除监听 移除方式二 + function函数
// arguments.callee 指的是函数自身 reqTaskOnHeadersReceived
// reqTask.offHeadersReceived(arguments.callee); --------------报错 ,在严格模式下是不行的,需要在非严格模式下
reqTask.offHeadersReceived(reqTaskOnHeadersReceived);
reqTask.abort();
})
// --------------------------------------------------------------
'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them;at RequestTask.onHeadersReceived callback function
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
const headersReceivedCallback = function (headers) {
// "use strict"
reqTask.offHeadersReceived(headersReceivedCallback)
console.log('headers', headers);
//在监听状态的时候,其实我们并没有拿到,有一个叫做statusCode,就是HTTP状态码的一个信息,
//但是我们可以依据Content-Length,可以拿它做一些事情
// Protected resource = 18 chars
// 能拿到这个长度,可能数据已经返回了,可以基于其它逻辑实施abort
// ~~ 两个波浪号表示,把它转义成整型的数字
if (~~headers.header['Content-Length'] < 19) reqTask.abort()
}
reqTask.onHeadersReceived(headersReceivedCallback)
// reqTask.abort()
# 具体根据业务需要
home接口,401,401代表是没有授权,因为user/home这个接口,发动接口请求,它是需要我们将登陆Token信息去带上它,
如果不带上这个信息,你请求这个资源,它返回的就是Protected resource,受保护的资源无法返回。
所以我们可以在请求接口的时候,如果我们发现,资源是受限的,不被允许的,那么就可以直接在这个阶段,就把请求给它abort掉。
这个就不需要去链接了,就是这样一个情况。
在我们abort掉以后,我们可以看到,/user/home这个请求会走到home-err里面
这节课我们主要学习了,wx.request接口,
下节课我们就要复用原来实现的微信一键登录代码,
在登录之后调用/user/home接口,这个接口先前我们了解过,它是一个需要登录凭证的这样一个接口