如果你使用 fetch() 进行后端 API 调用,你需要阅读此内容
自首次推出以来,Fetch API已经成为现代 Web 应用程序获取资源和与 Backend API 交互的事实标准。
虽然与XMLHttpRequest类似,但 fetch 提供了更强大的 API 和更灵活的功能集。它也可以用于window
以及 ,并且worker
还有像node-fetch这样的库允许它在 Node.js 中使用。基本上,fetch 几乎可以在任何地方、任何环境中使用。
它基于承诺的 API 使得异步加载资源变得非常简单,并且还可以轻松处理更复杂的情况,例如有条件地链接获取其他资源等。
虽然 fetch() 很棒并且确实解决了几乎所有 API 调用的麻烦,但在使用它时(或实际上任何其他方法,如XMLHttpRequest或axios等),我们最终不得不处理很多情况,从不同的错误代码,到网络请求失败的情况,将响应主体解析为 json 或文本,提取或解密错误原因以显示给用户或记录等。
这通常会导致每个后端 API 接口函数都重复大量的代码块。对于很多前端 Web 开发者来说,下面的代码片段看起来非常熟悉:
fetch(`${API_BASE_URL}/api/v1/categories`)
.then((response) => {
if ((response.status === 200) || (response.status === 400) || (response.status === 401)) {
return response.json();
}
})
.then((json) => {
if (!Object.keys(json).includes('errors')) {
// handle json.data
} else if (json.errors[0] === 'Invalid token.') { // in case of error, API returns array of error messages
// handle error due to invalid token, initiate re-login or something else
} else {
// handle any other error status codes
}
})
.catch(() => {
// handle any other case, like json parse failure or network error
});
显然,上述函数存在很多错误,但我们能否使其变得更好呢?
对于任何后端 API 方法,都会有表示成功情况的状态代码(200、201 等),以及在失败状态代码(如 401、404、500 等)的情况下表示错误的标准方法。
如果我们可以标准化后端 API 的接口并使用该标准化接口进行 API 调用,则上述代码可以大大简化并且不那么脆弱。
考虑到这一点,我们可以创建一种包装函数,使用 fetch() 包装我们的后端 API 调用,并为我们提供后端 API 调用结果的标准接口,无论成功还是失败。
我在许多前端代码库中使用了类似的函数,它确实有助于简化后端 API 调用并快速添加新方法。
const responseParserTypes = {
json: (response) => response.json(),
text: (response) => response.text(),
blob: (response) => response.blob(),
formData: (response) => response.formData(),
arrayBuffer: (response) => response.arrayBuffer(),
};
const parseResponse = (response, type) => {
if (!Object.keys(responseParserTypes).includes(type)) {
return null;
}
return responseParserTypes[type](response);
};
const fetchHandler = (
fetchPromise,
{
handledStatusCodes = [200],
parseHandledResponseAs = 'json',
parseUnhandledResponseAs = 'text',
getUnhandledResponseMessage = () => 'Error occured',
getFailureMessage = () => 'Error occured',
},
) => {
if (!Object.keys(responseParserTypes).includes(parseHandledResponseAs)) {
throw new Error(`parseHandledResponseAs shouwld be one of [${Object.keys(responseParserTypes).join(', ')}]`);
}
if (!Object.keys(responseParserTypes).includes(parseUnhandledResponseAs)) {
throw new Error(`parseUnhandledResponseAs shouwld be one of [${Object.keys(responseParserTypes).join(', ')}]`);
}
return new Promise((resolve, reject) => {
fetchPromise
.then((response) => {
if (handledStatusCodes.includes(response.status)) {
const parseResponsePromise = parseResponse(response, parseHandledResponseAs);
parseResponsePromise
.then((parsedResponse) => resolve(parsedResponse))
.catch((e) => reject(getFailureMessage(e)));
} else {
const parseResponsePromise = parseResponse(response, parseUnhandledResponseAs);
parseResponsePromise
.then((parsedResponse) => reject(getUnhandledResponseMessage(
response.status,
parsedResponse,
)))
.catch((e) => reject(getFailureMessage(e)));
}
})
.catch((e) => reject(getFailureMessage(e)));
});
};
export default fetchHandler;
您也可以在https://gist.github.com/SiDevesh/adaf910bc384574b776c370f77b9bedf找到它,将来可能还会有更多更新。
现在让我们看看如何callCategoriesIndexPageItemsLoad
使用上述函数简化相同的方法fetchHandler
。
export const getCategories = fetchHandler(
fetch(`${API_BASE_URL}/api/v1/categories`),
{
handledStatusCodes = [200],
parseHandledResponseAs = 'json',
parseUnhandledResponseAs = 'json',
getUnhandledResponseMessage = (statusCode, parsedResponseBody) => {
if (statusCode === 401) {
return 'Looks like you are logged out, redirecting to log in page...';
} else if (statusCode === 500) {
return 'Something went wrong, we are looking into it';
} else {
return 'Unknown error';
}
},
getFailureMessage = (e) => {
// return proper error message for other failures,
// like json parse error or network failure,
// that can be figured out using the exception argument provided
return 'Network error occured';
},
},
)
通过上述实现,我们将获得每个错误状态代码的正确错误消息以及可以在 UI 中显示的任何其他异常。
此外,这会自动处理响应的解析,因此无需链接response.json()
或reponse.text()
任何其他响应解析调用。
使用此方法获取数据非常简单:
getCategories()
.then((json) => {
// handle json.data
})
.catch((errorMessage) => {
// show errorMessage
});
这应该涵盖很多用例,如果需要在发生故障时执行操作,那么我们不仅可以返回和string
中的消息,还可以返回包含和或其他内容的消息的对象,然后可以对其进行检查,并执行相应的操作。getUnhandledResponseMessage
getFailureMessage
string
statusCode
就是这样,希望这能帮助您简化后端 API 调用方法。
如果您有更好的方法或知道有帮助的库,请告诉我。
希望这篇文章对您有帮助,如果有帮助的话,请在Twitter上关注我以获取更多类似的文章。
干杯!
鏂囩珷鏉ユ簮锛�https://dev.to/sidevesh/if-you-use-fetch-to-make-backend-api-calls-you-need-to-read-this-1dd7