1. 前言
目前,微信小程序已经成为了移动端开发中极受欢迎的平台之一,其实现的数据请求功能是小程序开发中十分重要的一个环节。相信大家都了解,小程序中进行网络请求,需要使用到 wx.request() 方法。
然而在实际开发中,wx.request() 方法有一个很大的缺陷,就是它不支持Promise。 这就需要开发者自己封装一套请求接口,以便于更加方便的进行接口的调用和数据的处理。
接下来将介绍我们是如何基于Promise 封装一个网络请求的功能。
2. 封装Promise
2.1 Promise 特点
Promise是ES6提供的一种全新的异步编程解决方案,具有以下特点:
Promise的状态不受外界影响,只有异步操作完成,才会改变状态。
Promise一旦状态改变,就不会再变,任何时候都可以得到这个结果。
Promise对象的错误会被吞掉。所以在Promise封装中要特别处理错误。
2.2 Promise封装请求
我们这里封装了一个requestPromise方法来处理小程序中的请求操作。
const API_PREFIX = 'https://www.example.com/'
const requestPromise = options => {
return new Promise((resolve, reject) => {
wx.request({
url: API_PREFIX + options.url,
method: options.method || 'GET',
data: options.data || {},
header: options.header || {
'Content-Type': 'application/json'
},
success: res => {
if (res.statusCode === 200) {
resolve(res)
} else {
reject(res)
}
},
fail: error => {
reject(error)
}
})
})
}
// example
requestPromise({
url: 'user/userinfo',
method: 'POST',
data: {
username: 'xiaoming',
age: 20
},
header: {
'authorization': 'Bearer token'
},
}).then(res => {
console.log(res.data)
}).catch(error => {
console.log(error)
})
上述代码将wx.request作为一个封装后的方法返回了,将其返回值改为了Promise,这样使用时就可以使用then和catch方法处理成功或者失败的回调。
3. 拦截器
3.1 概述
拦截器可以对请求进行统一处理,包括请求之前的统一处理和响应之后的统一处理。在需要对所有请求都进行特定的预处理时,拦截器非常有用。比如可以添加 authorization 等参数,或者在请求前加入全局loading等。
3.2 实现
我们可以自定义一个中间件,来达到拓展的目的,中间件主要分为两种:请求拦截和响应拦截。下面分别介绍一下相应的内容。
3.2.1 请求拦截器
在请求前拦截请求,并加入请求数据或者header头信息。下面是一个完整的请求拦截器实现过程
首先定义一个RequestMiddware的中间件类,用来存放拦截器相关的信息:
class RequestMiddware {
constructor() {
this._middlewares = []
}
}
然后在RequestMiddware原型链上定义一个 use() 方法,用于注册请求拦截器,该方法接收一个函数作为参数:
RequestMiddware.prototype.use = function (fn) {
if (typeof fn !== 'function') {
throw new TypeError('middleware must be a function')
}
this._middlewares.push(fn)
}
在请求前遍历所有的中间件进行处理,最终返回修改后的options,在requestPromise中处理这些中间件:
requestPromise.middlewares = new RequestMiddware()
const requestPromise = options => {
return new Promise((resolve, reject) => {
const chain = []
// 请求前拦截
requestPromise.middlewares._middlewares.forEach(fn => {
chain.push(fn)
})
chain.push(request(options))
// 请求后拦截
const next = response => {
return response
}
let index = 0
const execute = data => {
const currentMiddleware = chain[index]
index++
if (currentMiddleware) {
return currentMiddleware(data, execute)
} else {
return data
}
}
execute(options)
})
}
这样,在requestPromise方法内部,就会自动对中间件进行遍历和执行了,遇到错误或者请求/响应时加入需要做的拦截操作。
3.2.2 响应拦截器
接下来介绍一个类似于请求拦截器的响应拦截器。responseMiddleware的核心点在于,使用调用栈来进行中间件的遍历,同时还需要对错误进行包装。
定义一个ResponseMiddware的中间件类,用来存放拦截器相关的信息:
class ResponseMiddware {
constructor() {
this._middlewares = []
}
}
然后在ResponseMiddware原型链上定义一个 use() 方法,用于注册请求拦截器,该方法接收一个函数作为参数:
ResponseMiddware.prototype.use = function (fn) {
if (typeof fn !== 'function') {
throw new TypeError('middleware must be a function')
}
this._middlewares.push(fn)
}
在响应后遍历所有的中间件进行处理,最终返回修改后的options,在调用resolve方法。
requestPromise.middlewares = new RequestMiddware()
requestPromise.middlewares = new ResponseMiddware()
const requestPromise = options => {
return new Promise((resolve, reject) => {
const chain = []
// 请求前拦截
requestPromise.middlewares._middlewares.forEach(fn => {
chain.push(fn)
})
chain.push(request(options))
// 响应拦截
responseHandler = data => {
const {statusCode} = data || {};
if (statusCode !== 200) {
console.log('responseError')
requestPromise.middlewares._middlewares.forEach(fn => {
const error = new Error(`Request faild with status code ${statusCode}`)
error.statusCode = statusCode
fn(error)
})
return Promise.reject({
statusCode: statusCode,
error: data.errMsg
})
}
return data
}
chain.push(responseHandler)
// 响应后拦截
const next = response => {
return response
}
let index = 0
const execute = data => {
const currentMiddleware = chain[index]
index++
if (currentMiddleware) {
return currentMiddleware(data, execute)
} else {
return data
}
}
execute(options).then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
})
}
总结
整个封装的流程大致如下:
首先定义一个Promise,其将wx.request封装起来,并且返回数据。
定义一个RequestMiddware类和一个ResponseMiddware类,用于存放请求拦截器和响应拦截器的相关信息。
在requestPromise和requestPromise.middlewares中分别实例化这两个中间件类。
在requestPromise函数中,对请求的参数和header等信息进行处理。
在requestPromise函数中,使用requestPromise.middlewares._middlewares和execute方法分别遍历请求拦截器和响应拦截器进行处理,之后将处理后的结果返回。
最后,在执行所有操作之前,需要使用request来处理请求数据。
该方法的好处是封装了数据请求方法,使代码更加简洁和可维护,易于使用和处理错误。同时也方便开发者添加拦截器进行个性化定制,提高了代码的可扩展性和可重用性。希望对大家在开发小程序时具有一定的帮助。