likes
comments
collection
share

微信小程序 wx.request 封装(构建-请求拦截、响应拦截)

作者站长头像
站长
· 阅读数 15

一个优雅的前端,搬的每一块砖都必须是优雅,美观的。那我们就先从请求封装开始吧! (如果有使用 uni的小伙伴,一样可以使用,把 wx. 替换成 uni. 就可以了)

请求封装的代码

function isObject(obj) {
	return Object.prototype.toString.call(obj) === '[object Object]';
}
function forEach(obj, fn) {
	for (var key in obj) {
		if (Object.prototype.hasOwnProperty.call(obj, key)) {
			fn(obj[key], key);
		}
	}
}
// 对象合并 === 如果你的工具库中已有该方法的实现,可以将其替换 ===
export function merge() {
	var result = {};
	function assignValue(val, key) {
		if (isObject(result[key]) && isObject(val)) {
			result[key] = merge(result[key], val);
		} else {
			result[key] = val;
		}
	}
	for (var i = 0, l = arguments.length; i < l; i++) {
		forEach(arguments[i], assignValue);
	}
	return result;
}
// http规则校验
function urlRegExp(value) {
	return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value)
}

class Http {
    constructor(config = {}) {
        this.config = merge({}, {
                baseUrl: '', // 请求的根域名
                header: {}, // 默认的请求头
                method: 'POST',
                dataType: 'json',
                responseType: 'text', // 此参数无需处理,因为5+和支付宝小程序不支持,默认为text即可
                loading: true, // 默认请求是否开启loading
		}, config)
		// 拦截器
		this.interceptor = {
                // 请求前的拦截
                request: null,
                // 请求后的拦截
                response: null
        }
}

	// 主要请求部分
	request(options = {}) {
		let requestTask = {}
		if (options.loading === undefined) options.loading = this.config.loading
		// 检查请求拦截
		if (this.interceptor.request && typeof this.interceptor.request === 'function') {
			let tmpConfig = {};
			let interceptorRequest = this.interceptor.request(options);
			if (interceptorRequest === false) {
				// 返回一个处于pending状态中的Promise,来取消原promise,避免进入then()回调
				return new Promise(() => {});
			}
			this.options = interceptorRequest;
		}
		options.dataType = options.dataType || this.config.dataType;
		options.responseType = options.responseType || this.config.responseType;
		options.url = options.url || '';
		options.params = options.params || {};
		options.header = merge({}, this.config.header, options.header);
		options.method = options.method || this.config.method;

		return new Promise((resolve, reject) => {
			options.complete = (response) => {
				response.loading = options.loading
				// 判断是否存在拦截器
				if (this.interceptor.response && typeof this.interceptor.response === 'function') {
					let resInterceptors = this.interceptor.response(response);
					// 如果拦截器不返回false,直接接入then回调
					if (resInterceptors !== false) {
						resolve(resInterceptors);
					} else {
						// 如果拦截器返回false,意味着拦截器定义者认为返回有问题,直接接入catch回调
						reject(response.data || response);
					}
				} else {
					// 如果要求返回原始数据,就算没有拦截器,也返回最原始的数据
					resolve(response);
				}
			}
			// 判断用户传递的URL是否/开头,如果不是,加上/,
			options.url = urlRegExp(options.url) ? options.url : (this.config.baseUrl + options.url);

			// 发送请求
			requestTask = wx.request(options);
			if (options.setCancelToken) options.setCancelToken(requestTask)
		})
	}
}
export default Http

使用demo:这里我们新建一个request.js文件

将刚刚封装好的http文件引入,利用请求响应拦截器做一些请求的配置

const ACCESS_TOKEN = 'AurhToken' // token凭证的key

import HTTP from './http.js'
// 创建配置信息
const Config = {
	baseUrl: '', // 公共请求前缀(域名)
	timeout: 10 * 1000, // 请求超时时间
	loading: true // 是否启用pending状态的loading遮罩
}
// 初始化请求实例
const HttpClint = new HTTP(Config)

// 请求拦截配置项
const LoadingDelayTime = 300 // showLoading 延迟时间
let requestNum = 0 // 请求次数
let showLoading = false // loading 状态
let loadingTimer = null // showLoading 定时器
let RedirectTimer = null // 重新登录 定时器

// 请求拦截器
HttpClint.interceptor.request = config => {
	// 添加loading
	if (config.loading) {
		requestNum++
		// 请求队列中,第一个请求时,创建loading
		if (requestNum === 1) {
			loadingTimer = setTimeout(() => {
				showLoading = true
				wx.showLoading({
					title: 'loading...',
					mask: true
				})
			}, LoadingDelayTime)
		}
	}
	// 添加 Token 凭证
	if (typeof config.header !== 'object') config.header = {}
	config.header[ ACCESS_TOKEN ] = 'This is a token content'
	return config
}
// 响应拦截器
HttpClint.interceptor.response = response => {
	// 关闭 Loading
	if (response.loading) {
		requestNum--
		if (requestNum === 0) {
			if (loadingTimer) {
				clearTimeout(loadingTimer)
				loadingTimer = null
			}
			if (showLoading) {
				showLoading = false
				wx.hideLoading()
			}
		}
	}
  /* 以下是一个 响应统一处理 的示例,可以根据自己的场景业务进行修改 */
	if ([200, 201].includes(response.statusCode)) {
		if (response.header['Transfer-Encoding']) {
			return response.data
		} else if (response.data.code !== 0) {
			wx.showToast({ title: response.data.message || '网络错误', icon: 'none' })
			return false
		}
		return response.data
	} else {
		if (response?.data?.code === 2001) {
			wx.showToast({ title: '登录过期', icon: 'none', mask: true })
			setTimeout(() => {
				wx.navigateTo({ url: '/pages/login/login' })
			}, 1000)
			return false
		}
                // 不是主动取消的请求给出提示
		if (response?.errMsg !== 'request:fail abort') {
			wx.showToast({ title: '网络错误', icon: 'none' })
		}
		return false
	}
}

export default HttpClint

tips

最后就是在小程序中各个模块中的使用了,在app.js中引入我们封装好的请求方法,最后抛出就ok了。

附app.js示例代码:

import HttpClint from './utils/request.js'

App({
    $Http: HttpClint
})

附请求示例代码:

// pages/home/home.js
const App = getApp()

page({
    onLoad() {
        this.getDetail()
    },
    getDetail() {
        const params = {
                url: '/api/detail/get', // 请求api
                method: 'POST',
                data: { id: 123, type: 1 },
                loading: true // 是否开启loading,可选 默认 true
                // 如果有取消请求的场景,可以使用 setCancelToken 钩子进行收集,返回参数是请求实例
                setCancelToken: task => { console.log(task) }
        }
        App.$Http.request(params).then(res => {
            // 请求成功
            console.log(res)
        })
    }
 })

转载自:https://juejin.cn/post/6977247932051537933
评论
请登录