Last active
March 28, 2024 02:47
-
-
Save teal-front/b523485d0da182a0bf6132c7691b4ed5 to your computer and use it in GitHub Desktop.
project-snippets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* fetch api | |
* 1. 确保返回 fulfilled promise,没有rejected promise,所以也不用处理错误 | |
* 带错误的Promise<[null, data]> | |
* 正常结果的Promise<[{code: number, msg: string}]> | |
* 2. 使用了signal来处理超时情况 | |
*/ | |
// 如果是sdk项目,使用ponyfill,如果是自己的项目,使用polyfill(isomorphic-fetch) | |
import fetchPonyfill from "fetch-ponyfill"; | |
import pickBy from "lodash/pickBy"; | |
const {fetch} = fetchPonyfill(); | |
const MAX_TIME = 30000; | |
request.get = function (path, payload = {}) { | |
return request(path, payload, "GET"); | |
}; | |
request.post = function (...args) { | |
return request(...args, "POST"); | |
}; | |
export function request(url, payload = {}, method = "POST") { | |
const controller = typeof AbortController === "function" | |
? new AbortController() | |
: { | |
abort: () => ({}), | |
signal: null, | |
}; | |
const id = setTimeout(() => controller.abort(), MAX_TIME); | |
const requestOptions = { | |
headers: { | |
// 根据实际请求来添加自定义headers | |
"Content-Type": "application/json; charset=utf-8", | |
}, | |
method, | |
signal: controller.signal, | |
}; | |
if (method === "POST") { | |
requestOptions.body = payload instanceof FormData ? payload : JSON.stringify(payload); | |
} else if (method === "GET") { | |
const packPayload = pickBy( | |
payload, | |
v => !(v === undefined || v === null), | |
); | |
if (Object.keys(packPayload).length) { | |
url += `?${new URLSearchParams(packPayload)}`; | |
} | |
} | |
return fetch(url, requestOptions) | |
.then((res) => { | |
if (!res.ok) { | |
return res.json(); | |
} | |
// 兼容blob类型的返回 | |
// 当要手动处理下载的文件时,转换responseType为blob | |
return requestOptions.responseType === 'blob' ? res.blob() : res.json(); | |
}) | |
.then((data) => { | |
// 当要手动处理下载的文件时,直接返回blob类型的数据 | |
if (data instanceof Blob) return [null, data]; | |
if (data.retCode !== 0) { | |
throw data; | |
} | |
const {retCode, retMsg, ...restData} = data; | |
return [null, restData]; | |
}) | |
.catch(e => { | |
// 网络层的超时、CORS错误等会直接走到catch处理 | |
// CORS错误name为TypeError | |
// 超时的错误nameAbortError | |
if (e instanceof Error) { | |
return [{code: -1, msg: e.message}, null]; | |
} | |
// !res.ok从这里抛出的错误时,e为{code,msg} | |
if (e.code) { | |
return [e, null]; | |
} | |
// 从data.retCode处返回的错误时,e为{retCode, retMsg} | |
return [{code: e.retCode, msg: e.retMsg || "网络错误,请稍后重试"}, null]; | |
}) | |
.finally(() => { | |
clearTimeout(id); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment