接口请求超时设置

2,262 阅读2分钟

一、场景

页面请求接口受当前网络的友好程度影响,若迟迟不能请求,应取消相关请求。

二、不同接口交互方式下的超时设置

以下列出了始终前后端的交互方式,其中前三项都是自带了 timeout 参数,设置相应的超时时间即可,但是在使用 fetch 时,超时时间设置不见了。ES6 以后 Promise 出现解决地狱回调的方式:

var promise1 = () => {
    return new Promise((resolve, reject) => {});
};
var promise2 = () => {
    return new Promise((resolve, reject) => {});
};
Promise.race([promise1, promise2]); // 传入多个Promise对象,等待最快对象完成
Promise.all([promise1, promise2]); // 传入多个Promise 对象,等待所有对象完成

于是可以结合函数 setTimeout 实现 fetch 的超时设置

2.1、XMLHttpRequest 原生接口请求方式

let xhr = new XMLHttpRequest();
xhr.timeout = 3000; // 设置xhr请求的超时时间
xhr.open('post', 'http://172.16.0.92/xxx', true);
xhr.ontimeout = function (e) {
    console.log('请求超时:', e);
};
xhr.send();

2.2、Ajax jQuery 封装的请求方式

$.ajax({
    timeout: 3000, // 设置超时时间
});

2.3、axios 它本身是对原生 XHR 的封装

axios({
    method: 'post',
    url: '/user/12345',
    timeout: 3000, // 设置超时时间
    data: {
        firstName: 'Fred',
        lastName: 'Flintstone'
    }
});
  • 支持 node,创建 http 请求;
  • 支持 Promise API
  • 客户端防止 CSRF:每个请求带一个 cookie 拿到的 key
  • 拦截请求和响应;
  • 可取消请求。

2.4、fetch 基于 Promise 的异步处理机制

/**
 * @param {String} url 接口地址
 * @param {Object} option 配置参数
 * @description fetch 请求封装
*/
function fetchHttp(url, option) {
    var newOptions = {
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json; charset=utf-8',
        },
        mode: 'cors',
        redirect: 'follow',
        referrer: 'no-referrer',
        method: option.method,
        body: option.body,
        // ...option,
    };

    // if ( ['POST', 'PUT', 'DELETE'].includes(option.method)) {
    if (option.method === 'POST' || option.method === 'PUT' || option.method === 'DELETE') {
        if (!(option.body instanceof FormData)) {
            newOptions.body = JSON.stringify(newOptions.body);
        }
    }

    // 添加超时拦截请求
    var controller = new AbortController();
    var signal = controller.signal;
    // 任务1:超时定时任务
    var timeoutPromise = () => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(new Response('timeout', { status: 504, statusText: 'timeout ' }));
                controller.abort();
            }, timeout);
        });
    }
    // 任务2:接口请求
    var requestPromise = () => {
        newOptions.signal = signal;
        return fetch(url, newOptions)
            .then(function (response) {
                if (option.method === 'DELETE' || response.status === 204) {
                    return response.text();
                }
                return response.json();
            })
            .then(function (res) {
                if (option.callback) option.callback(res);
                return res;
            })
            .catch(function (error) {
                console.error('监控接口请求出错:', error);
            });
    };

    // 执行多个任务:等待最快对象完成
    Promise.race([timeoutPromise(), requestPromise()])
        .then(resp => {
            console.log(resp);
        })
        .catch(error => {
            console.log('请求超时:', e);
        });
}
  • Promise.race(iterable) 方法返回一个 Promise,一旦迭代器中的某个 Promise 解决或拒绝,返回的 Promise 就会解决或拒绝。
  • 更加底层,提供的API丰富 request, response
  • 语法简单,脱离了XHR,基于ES新的 Promise 设计。

2.5、 Beacon

接口用于将异步和非阻塞请求发送到服务器。Beacon 请求使用 HTTP 协议中的 POST 方法,请求通常不需要响应。这个请求被保证在,页面的 unload 状态从发起到完成之前被发送。且不会产生请求阻塞,影响页面性能,所以不需要设置超时。更多内容详见 sendBeacon 实现数据上报

三、参考网址