最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 微信小程序请求封装(构建请求拦截/响应拦截)

    正文概述 掘金(兮丶)   2021-06-24   792

    补充一篇关于微信小程序项目的基础封装,请求封装篇

    如果有使用 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)
            })
        }
     })
    
    

    起源地下载网 » 微信小程序请求封装(构建请求拦截/响应拦截)

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元