From 1b0e9d304244e3e05c01f3423528165224cba2b8 Mon Sep 17 00:00:00 2001 From: wzhqwq Date: Mon, 9 Aug 2021 23:49:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=AF=B9=E8=AF=B7=E6=B1=82?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E7=9A=84=E9=80=BB=E8=BE=91=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/helper/axios.js | 53 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 147aa02..0faed49 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ 请根据`env.example.json`的格式按照自己的需求编写`env.json`,或者直接运行`cp env.example.json env.json`,**否则无法正确处理网络请求!** ### 网络请求的用法 -引入./src/helper/axios.js(请以相对路径引入),尽情使用其中的post、get方法,它们会返回一个Promise(或可被视作Promise的AsyncFunction),且不会以抛出异常的方式通知网络错误,它会在服务器返回内容中插入属性`networkStatus`,**当值为200时才可以视作正确的服务器响应**,当值为-1时说明这是用户的网络错误,**你不需要处理200以外的情况,代码能够发出弹窗并建议用户重试** \ No newline at end of file +引入./src/helper/axios.js(请以相对路径引入),尽情使用其中的post、get方法,它们会返回一个Promise(或可被视作Promise的AsyncFunction),且为方便不会以抛出异常的方式通知网络错误。它会在服务器返回内容中插入属性`networkStatus`,**当值为200时才可以视作正确的服务器响应**,当值为-1时说明这是用户的网络错误。**你不需要处理200以外的情况,代码能够发出弹窗并建议用户重试** \ No newline at end of file diff --git a/src/helper/axios.js b/src/helper/axios.js index dcf001d..b145ac1 100644 --- a/src/helper/axios.js +++ b/src/helper/axios.js @@ -3,7 +3,7 @@ import { failed } from './alert'; import qs from 'qs'; import History from './history'; -export function get(url) { +export function get(url, evoker) { return send( axios.get(url, { headers: { @@ -11,10 +11,13 @@ export function get(url) { "Allow-Control-Allow-Origin": "*" } }), - { fn: () => get(url), identifier: 'get:' + url } + { + fetcher: () => get(url, evoker), + identifier: 'get:' + url + (evoker ? `@${evoker}` : '') + } ); } -export function post(url, data) { +export function post(url, data, evoker) { return send( axios.post(url, qs.stringify(data), { headers: { @@ -22,7 +25,10 @@ export function post(url, data) { "Allow-Control-Allow-Origin": "*" } }), - { fn: () => post(url, data), identifier: 'post:' + url + ' ' + JSON.stringify(data) } + { + fetcher: () => post(url, data, evoker), + identifier: 'post:' + url + (evoker ? `@${evoker}` : '') + } ); } @@ -30,9 +36,19 @@ const waitToSend = []; async function send(xhr, retryConf) { if (waitToSend.length) { - if (waitToSend.every(retryConfItem => retryConfItem.identifier !== retryConf.identifier)) - waitToSend.push(retryConf); - return; + // 等待列表不为空,说明需要等待用户决定是否重试,这也提高了目前请求的成功率 + return await new Promise(res => { + if (waitToSend.every(retryConfItem => retryConfItem.identifier !== retryConf.identifier)) + waitToSend.push({ ...retryConf, resolver: res }); + else + waitToSend + .filter(retryConfItem => retryConfItem.identifier === retryConf.identifier) + .forEach(retryConfItem => { + retryConfItem.resolver({ networkStatus: -2, status: false }); + retryConfItem.resolver = res; + }); + // 虽然说理论上filter的结果只会有一个,但是还是要forEach一下,因为写起来方便hhhh + }); } try { const { data } = await xhr; @@ -49,11 +65,18 @@ async function send(xhr, retryConf) { }; if (err?.response?.status === 401) { History.force('/login'); + feedWaitList(failData); + // 若是认证问题导致的错误,则没有必要继续后面等待的请求,且强制跳转后重试可能会导致已卸载的组件被更新 return failData; } + + if (!waitToSend.length) return failData; waitToSend.push(retryConf); + // 等待列表不为空时弹框要么出现了要么就是在消失的路上,没有办法给予用户点击重试的机会,所以交由外部逻辑处理 + + // 注意,理论上带有时间戳的请求是不可以重试的,但是这里不做那方面考虑,如果未来有需要,可以自己实现一个刷新时间戳重试的逻辑 if (err.message === 'Network Error') - return await failed('您的设备似乎断网了,请检查网络后重试或刷新', flushWaitList) || failData; + return await failed('您的设备似乎断网了,或者服务器发生了问题,请检查网络后重试或刷新', flushWaitList) || failData; if (!err?.response?.status) return await failed('请求发生问题:' + err.message, flushWaitList) || failData; if (err.response.status === 504) @@ -63,7 +86,19 @@ async function send(xhr, retryConf) { } function flushWaitList() { - let fns = waitToSend.map(item => item.fn); + let fns = waitToSend.map( + conf => + async () => conf.resolver(await conf.fetcher()) + ); + waitToSend.splice(0, waitToSend.length); + fns.forEach(fn => fn()); +} + +function feedWaitList(data) { + let fns = waitToSend.map( + conf => + () => conf.resolver(data) + ); waitToSend.splice(0, waitToSend.length); fns.forEach(fn => fn()); } \ No newline at end of file