如果有使用 uni的小伙伴,一样可以使用,把 wx.
替换成 uni.
就可以了
定义一个深度拷贝的方法,用来参数的合并 放在help模块文件中
// JS对象深度合并
export function deepMerge( target = {}, source = {} ) {
target = deepClone( target );
if ( typeof target !== 'object' || typeof source !== 'object' ) return false;
for ( const prop in source ) {
if ( !source.hasOwnProperty( prop ) ) continue;
if ( prop in target ) {
if ( typeof target[ prop ] !== 'object' ) {
target[ prop ] = source[ prop ];
} else {
if ( typeof source[ prop ] !== 'object' ) {
target[ prop ] = source[ prop ];
} else {
if ( target[ prop ].concat && source[ prop ].concat ) {
target[ prop ] = target[ prop ].concat( source[ prop ] );
} else {
target[ prop ] = deepMerge( target[ prop ], source[ prop ] );
}
}
}
} else {
target[ prop ] = source[ prop ];
}
}
return target;
}
复制代码
定义一个url的正则校验方法 放在validate模块文件中
/**
* 验证URL格式
*/
export function urlRegExp( value ) {
return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test( value )
}
复制代码
请求封装的代码
import {
deepMerge
} from './help.js'
import {
urlRegExp
} from './validate.js'
class Http {
constructor( ) {
this.config = {
// 请求的根域名
baseUrl: '',
// 默认的请求头
header: {},
method: 'POST',
// 设置为json,返回后wx.request会对数据进行一次JSON.parse
dataType: 'json',
// 此参数无需处理
responseType: 'text',
// 默认请求是否开启loading
loading: true,
}
// 拦截器
this.interceptor = {
// 请求前的拦截
request: null,
// 请求后的拦截
response: null
}
// get请求
this.get = ( url, data = {}, loading = this.config.loading, header = {} ) => {
return this.request( {
method: 'GET',
url,
header,
data
}, loading )
}
// post请求
this.post = ( url, data = {}, loading = this.config.loading, header = {} ) => {
return this.request( {
url,
method: 'POST',
header,
data
}, loading )
}
// put请求
this.put = ( url, data = {}, loading = this.config.loading, header = {} ) => {
return this.request( {
url,
method: 'PUT',
header,
data
}, loading )
}
// delete请求
this.delete = ( url, data = {}, loading = this.config.loading, header = {} ) => {
return this.request( {
url,
method: 'DELETE',
header,
data
}, loading )
}
}
// 设置全局默认配置
create( customConfig ) {
// 深度合并对象,否则会造成对象深层属性丢失
this.config = deepMerge( this.config, customConfig );
}
// 主要请求部分
request( options = {}, loading = this.config.loading ) {
options.loading = 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 = Object.assign( this.config.header, options.header );
options.method = options.method || this.config.method;
return new Promise( ( resolve, reject ) => {
options.complete = ( response ) => {
response.loading = 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
.indexOf( '/' ) == 0 ?
options.url : '/' + options.url ) );
wx.request( options );
} )
}
}
export default Http
复制代码
使用demo:这里我们新建一个request.js文件
将刚刚封装好的http文件引入,利用请求响应拦截器做一些请求的配置
const ACCESS_TOKEN = 'AurhToken' // token凭证的key
import HTTP from './http.js'
// 创建配置信息
const requestConfig = {
baseUrl: '', // https://test.request.api
timeout: 10 * 1000, // 请求超时时间
}
// 初始化请求实例
const newHttp = new HTTP( )
newHttp.create( requestConfig )
// 请求拦截配置项
const LoadingDelayTime = 750 // showLoading 延迟时间
let requestNum = 0 // 请求次数
let showLoading = false // loading 状态
let loadingTimer = null // showLoading 定时器
let RedirectTimer = null // 重新登录 定时器
// 请求拦截器
newHttp.interceptor.request = config => {
// 添加loading
if ( config.loading ) {
requestNum++
if ( showLoading ) return
showLoading = true
loadingTimer = setTimeout( ( ) => {
wx.showLoading( {
title: 'loading...',
mask: true
} )
}, LoadingDelayTime )
}
// 添加 Token 凭证
if ( typeof config.header !== 'object' ) config.header = {}
config.header[ ACCESS_TOKEN ] = 'This is a token content'
// 这里可以自定义统一处理一下 请求的参数
// config.data = buildOptions( config.data )
return config
}
// 响应拦截器
newHttp.interceptor.response = response => {
// 关闭 Loading
if ( response.loading ) {
requestNum--
if ( requestNum === 0 ) {
if ( showLoading ) {
showLoading = false
if ( loadingTimer ) {
clearTimeout( loadingTimer )
loadingTimer = null
}
wx.hideLoading( )
}
}
}
// 错误统一处理
if ( response.statusCode === 200 ) {
const {
code,
message
} = response.data
switch ( code ) {
case 0: // 成功响应
return response.data
break;
case 401: // 登录凭证过期 重新登录
// 这里做一个定时器防抖,防止多个请求返回401,重复执行
if ( RedirectTimer ) clearTimeout( RedirectTimer )
RedirectTimer = null
RedirectTimer = setTimeout( ( ) => {
wx.showToast( {
title: `请先登录`,
icon: 'none',
duration: 1500
} )
let timerS = setTimeout( ( ) => {
clearTimeout( timerS )
// 这里做退出登录的操作
// ......
}, 1500 )
}, 2000 )
return false
break;
default:
wx.showToast( {
title: message || '网络错误1',
icon: 'none'
} )
return false
}
} else {
wx.showToast( {
title: '网络错误2',
icon: 'none',
duration: 2000
} )
return false
}
}
//GET请求
export function requestGet( {
url,
data = {},
loading = true,
header = {}
} ) {
return newHttp.get( url, data, loading, header )
}
//POST请求
export function requestPost( {
url,
data = {},
loading = true,
header = {}
} ) {
return newHttp.post( url, data, loading, header )
}
// PUT请求
export function requestPut( {
url,
data = {},
loading = true,
header = {}
} ) {
return newHttp.put( url, data, loading, header )
}
// DELETE请求
export function requestDelete( {
url,
data = {},
loading = true,
header = {}
} ) {
return newHttp.delete( url, data, loading, header )
}
复制代码
tips
最后就是在小程序中各个模块中的使用了,在app.js中引入我们封装好的请求方法,最后抛出就ok了。
附app.js示例代码:
import { requestGet,requestPost,requestPut,requestDelete } from './utils/request.js'
App({
$Http: {
get: requestGet,
post: requestPost,
put: requestPut,
delete: requestDelete
}
})
复制代码
附请求示例代码:
// pages/home/home.js
const App = getApp()
page({
onLoad() {
this.getDetail()
},
getDetail() {
const params = {
// 请求api
url: '/api/detail/get',
// 请求参数
data: {
id: 123,
type: 1
},
// 是否开启loading,可选 默认 true
loading: true
}
App.$Http.post(params).then(res => {
// 请求成功
console.log(res)
})
}
})