资讯专栏INFORMATION COLUMN

记让一个http请求支持拦截器

Zoom / 1236人阅读

摘要:但是在使用过程中,发现这个框架自带的请求库特别简单,于是参照手动封装了一下,使其支持和拦截器。链是个数组,然后把请求拦截器放到真正请求的前面,响应后的拦截器放在真请求的后面。

最近想用全js系统的写一遍前后端学习一下,就创建了一套TODOList项目练手。当前仅写完了后端demo,前端正在使用vue。并且准备以后再用react和flutter再写一遍。
此项目
后端demo
前提

在写练手项目的时候使用了Framework7这个移动端ui框架,因为这个框架的动画写的很厉害所以选择了它。但是在使用过程中,发现这个框架自带的ajax请求库特别简单,于是参照axios手动封装了一下,使其支持promise和拦截器。

动手

废话不多说,上代码
comover.js

import { Request as F7Request } from "framework7";

// 将原始请求对象封装成Promise对象
function adapter(config) {
    return new Promise(function(resolve, reject) {
        F7Request({
            url: `${config.baseUrl}${config.url}`,
            method: config.method,
            headers: config.headers,
            data: config.data,
            success(data, status, xhr) {
                resolve({
                    data: JSON.parse(data),
                    status: status,
                    config: config,
                    xhr: xhr
                });
            },
            error(xhr, status) {
                let error = new Error(
                    `Request failed with status code ${status}`
                );
                error.xhr = xhr;
                reject(error);
            }
        });
    });
}

// 发送请求
function dispatchRequest(config) {
    return adapter(config).then(
        function onAdapterResolution(response) {
            return response;
        },
        function onAdapterRejection(reason) {
            return Promise.reject(reason);
        }
    );
}

export default class Comeover {
    interceptors = {};
    requestHandlers = [];
    responseHandlers = [];
    config = {};
    constructor(config = ({ baseUrl = "" } = {})) {
        const self = this;

        this.config = { ...config };

        this.interceptors = {
            request: {
                use(fulfilled, rejected) {
                    self.requestHandlers.push({
                        fulfilled,
                        rejected
                    });
                }
            },
            response: {
                use(fulfilled, rejected) {
                    self.responseHandlers.push({
                        fulfilled,
                        rejected
                    });
                }
            }
        };
        
        // ES6中class内方法运行时绑定上下文
        this.request = this.request.bind(this);
    }
    request(config) {
        // 合并默认config和发送请求时的config
        let inconfig = { ...this.config, ...config };
        
        // 创建Promise链
        let chain = [dispatchRequest, undefined];
        // 创建初始Promise链中传递的promise对象
        let promise = Promise.resolve(inconfig);
        
        // 将拦截器注入Promise链
        this.requestHandlers.forEach(interceptor => {
            chain.unshift(interceptor.fulfilled, interceptor.rejected);
        });
        this.responseHandlers.forEach(interceptor => {
            chain.push(interceptor.fulfilled, interceptor.rejected);
        });
        
        // 运行Promise链
        while (chain.length) {
            promise = promise.then(chain.shift(), chain.shift());
        }
        
        // 返回最终的promise对象
        return promise;
    }
}
使用

这个例子就是在所有请求前后使用nprogress假装显示一下请求进度

import Comeover from "./comeover";
import Np from "nprogress";

const baseUrl = process.env.NODE_ENV === "development" ? "" : /* 上线地址 */ "";

const comeover = new Comeover({ baseUrl });

comeover.interceptors.request.use(
    config => {
        Np.start();
        return config;
    },
    error => {
        Np.done();
        return Promise.reject(error);
    }
);
comeover.interceptors.response.use(
    response => {
        Np.done();
        return response;
    },
    error => {
        Np.done();
        return Promise.reject(error);
    }
);

export { request };
发请求
comeover.request({
    url: "/api/login",
    method: "post",
    data: {
        email: this.email,
        password: this.password
    }
})
    .then(({ data }) => {
        this.$store.commit("login", { token: data.message });
        router.back();
    })
    .catch(err => {
        app.dialog.alert("用户名或密码错误", "登陆失败");
    });
总结

还可以参照axios继续封装多带带的get、post等等的方法,这个demo就不写了。
Promise链是个数组,然后把请求拦截器放到真正请求的前面,响应后的拦截器放在真请求的后面。然后以resolve在前,reject在后的顺序,成对循环注入到promise.then中。而真正请求的resovereject是写在dispatchRequest里的,所以dispatchRequest这里没有reject,要加一个undefined
ES6的实例化方法多带带使用的时候this指向会有问题,需要多带带处理

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106911.html

相关文章

  • JS HTTP 请求终极解决方案 - fly.js

    摘要:支持请求响应拦截器。定位与目标的定位是成为请求的终极解决方案。拦截器支持请求响应拦截器,可以通过它在请求发起之前和收到响应数据之后做一些预处理。 Fly.js 是一个功能强大的轻量级的javascript http请求库,同时支持浏览器和node环境,通过适配器,它可以运行在任何具有网络能力的javascript运行环境;同时fly.js有一些高级的玩法如全局ajax拦截、在web a...

    OpenDigg 评论0 收藏0
  • ★推荐一款适用于SpringBoot项目的轻量级HTTP客户端框架

    摘要:请求重试拦截器错误解码器在发生请求错误包括发生异常或者响应数据不符合预期的时候,错误解码器可将相关信息解码到自定义异常中。 在SpringBoot项目直接使用okhttp、httpClient或者RestTemplate发起HTTP请求,既繁琐又不方便统一管理。因此,在这里推荐一个适...

    不知名网友 评论0 收藏0

发表评论

0条评论

Zoom

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<