开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 1425|回复: 0
收起左侧

[技术分享] uniapp request的封装参考

[复制链接]
发表于 2021-10-28 16:51:59 | 显示全部楼层 |阅读模式   广东省揭阳市

由于uniapp的网络请求uni.request的返回的回调函数,而且没有请求拦截得自行封装实现,但是发现uniapp的uview的框架封装的request很好用,于是抽离出来单独使用
这里是所需要工具函数的深度克隆和对象深度合并

// JS对象深度合并
function deepMerge(target = {}, source = {}) {
    target = deepClone(target);
    if (typeof target !== 'object' || typeof source !== 'object') return false;
    for (var 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;
}

// 深度克隆
function deepClone (obj) {
    // 对常见的“非”值,直接返回原来值
    if([null, undefined, NaN, false].includes(obj)) return obj;
    if(typeof obj !== "object" && typeof obj !== 'function') {
        //原始类型直接返回
        return obj;
    }
    var o = isArray(obj) ? [] : {};
    for(let i in obj) {
        if(obj.hasOwnProperty(i)){
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
        }
    }
    return o;
}

/**
 * 验证URL格式
 */
function testUrl(value) {
    return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value)
}

这里是以Request类的形式封装,使用是生成该Request类实例,请求拦截器可以在请求前执行传入回调函数,加token,加签名等,处理完才去进行网络请求,而响应拦截器是对响应的数据做格式化处理,注释里详细描述

class Request {
    // 设置全局默认配置
    setConfig(customConfig) {
        // 深度合并对象,否则会造成对象深层属性丢失
        this.config = deepMerge(this.config, customConfig);
    }

    // 主要请求部分
    request(options = {}) {
        // 检查请求拦截
        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) => {
            // 请求返回后,隐藏loading(如果请求返回快的话,可能会没有loading)
            uni.hideLoading();
            // 清除定时器,如果请求回来了,就无需loading
            clearTimeout(this.config.timer);
            this.config.timer = null;
            // 判断用户对拦截返回数据的要求,如果originalData为true,返回所有的数据(response)到拦截器,否则只返回response.data
            if(this.config.originalData) {
                // 判断是否存在拦截器
                if (this.interceptor.response && typeof this.interceptor.response === 'function') {
                    let resInterceptors = this.interceptor.response(response);
                    // 如果拦截器不返回false,就将拦截器返回的内容给this.$u.post的then回调
                    if (resInterceptors !== false) {
                        resolve(resInterceptors);
                    } else {
                        // 如果拦截器返回false,意味着拦截器定义者认为返回有问题,直接接入catch回调
                        reject(response);
                    }
                } else {
                    // 如果要求返回原始数据,就算没有拦截器,也返回最原始的数据
                    resolve(response);
                }
                } else {
                    if (response.statusCode == 200) {
                        if (this.interceptor.response && typeof this.interceptor.response === 'function') {
                            let resInterceptors = this.interceptor.response(response.data);
                            if (resInterceptors !== false) {
                                    resolve(resInterceptors);
                            } else {
                                    reject(response.data);
                            }
                        } else {
                        // 如果不是返回原始数据(originalData=false),且没有拦截器的情况下,返回纯数据给then回调
                            resolve(response.data);
                        }
                    } else {
                        // 不返回原始数据的情况下,服务器状态码不为200,modal弹框提示
                        // if(response.errMsg) {
                        //  uni.showModal({
                        //      title: response.errMsg
                        //  });
                        // }
                        reject(response)
                    }
                }
            }

            // 判断用户传递的URL是否/开头,如果不是,加上/,这里使用了uView的test.js验证库的url()方法
            options.url = testUrl(options.url) ? options.url : (this.config.baseUrl + (options.url.indexOf('/') == 0 ?
            options.url : '/' + options.url));

            // 是否显示loading
            // 加一个是否已有timer定时器的判断,否则有两个同时请求的时候,后者会清除前者的定时器id
            // 而没有清除前者的定时器,导致前者超时,一直显示loading
            if(this.config.showLoading && !this.config.timer) {
                this.config.timer = setTimeout(() => {
                    uni.showLoading({
                        title: this.config.loadingText,
                        mask: this.config.loadingMask
                    })
                    this.config.timer = null;
                }, this.config.loadingTime);
            }
            uni.request(options);
        })
        // .catch(res => {
        //  // 如果返回reject(),不让其进入this.$u.post().then().catch()后面的catct()
        //  // 因为很多人都会忘了写后面的catch(),导致报错捕获不到catch
        //  return new Promise(()=>{});
        // })
    }

    constructor() {
        this.config = {
            baseUrl: '', // 请求的根域名
            // 默认的请求头
            header: {},
            method: 'POST',
            // 设置为json,返回后uni.request会对数据进行一次JSON.parse
            dataType: 'json',
            // 此参数无需处理,因为5+和支付宝小程序不支持,默认为text即可
            responseType: 'text',
            showLoading: true, // 是否显示请求中的loading
            loadingText: '请求中...',
            loadingTime: 800, // 在此时间内,请求还没回来的话,就显示加载中动画,单位ms
            timer: null, // 定时器
            originalData: false, // 是否在拦截器中返回服务端的原始数据,见文档说明
            loadingMask: true, // 展示loading的时候,是否给一个透明的蒙层,防止触摸穿透
        }

        // 拦截器
        this.interceptor = {
            // 请求前的拦截
            request: null,
            // 请求后的拦截
            response: null
        }
}
export default new Request

上边的config的参数就不描述,当然也可以自定义实例化继承后自定义请求函数如上传图片等等,也能实时获取实例的配置信息

// get请求
this.get = (url, data = {}, header = {}) => {
    return this.request({
        method: 'GET',
        url,
        header,
        data
    })
}

// post请求
this.post = (url, data = {}, header = {}) => {
    return this.request({
        url,
        method: 'POST',
        header,
        data
    })
}

// put请求,不支持支付宝小程序(HX2.6.15)
this.put = (url, data = {}, header = {}) => {
    return this.request({
        url,
        method: 'PUT',
        header,
        data
    })
}

// delete请求,不支持支付宝和头条小程序(HX2.6.15)
this.delete = (url, data = {}, header = {}) => {
    return this.request({
        url,
        method: 'DELETE',
        header,
        data
    })
}
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表