日常搬砖的时候一定会需要发送请求,发送请求就必须要考虑到出错的情况。及时报错并且附上尽可能详细的信息,一定会方便自己及时解决问题。
如何写好一个try catch 就尤为重要。
为一个请求包上try catch
try{
const response = fetch(url, init)
}catch(err){
// console.log(err);
}
这就是一个简单的try catch .
那什么时候会报错呢? 答案是: 出现跨域等情况的时候。这时候根本没有response, fetch 率先抛出了错误。
但是,如果这个fetch返回了response,这个时候是不会报错的。因为try catch并不去检查 response是否ok.
(关于什么时候是ok的,看这Response.ok - Web APIs | MDN (mozilla.org))
对于前端来说,api返回的所有状态并不都是成功的,非200的状态都代表的后端出现了某种问题。
所以在response的状态不ok的时候,应该抛出一个错误。 为了更好地记录下错误信息,我们可以在基于Error,另起一个新的类,用于记录和传递error
Error 类型看这里Error - JavaScript | MDN (mozilla.org)
class HttpRequestError extends Error {
public readonly name: string = 'HttpRequestError';
public readonly url?: string;
public readonly response?: Response;
public constructor(init: HttpRequestErrorInit, options?: ErrorOptions) {
super(init.message ?? 'Http request failed.', options);
this.url = (init.url && String(init.url)) ?? init.response?.url;
this.response = init.response;
}
}
try{
const response = fetch(url, init)
if(!response.ok){
throw new HttpRequestError({
message: `Http request failed with status code ${response.status}`,
response,
url,
});
}
}catch(err){
throw err;
}
为一群请求包上try catch
很多时候,一次请求并不能完成整个业务逻辑。 需要有几个请求串行起来才能完成一个完整的业务操作。这其中每一次操作都有让整个操作失败的风险。
我们可以在组合操作分最外部包上try catch, 以此接收出现的错误。
给一个特例进行松绑
为了方便,我们会把fetch的操作进行一个包装,以此复用代码,增加效率和可读性。但是总有那么一两个api,需要我们包容404或者其他的情况,这时候,为了不让报错中断整个业务链路的执行,我们可以在某个特定的请求中包裹一个try catch, 在特殊的情况中,把一些状况忽略掉。
下面的例子就展示了,当接口返回404时,我们正常的返回一个设计好的值。并且终止当前的操作。
function _fetch(url, init){
try{
const response = fetch(url, init)
if(!response.ok){
throw new HttpRequestError({
message: `Http request failed with status code ${response.status}`,
response,
url,
});
}
}catch(err){
throw err;
}
}
function getSomeInfo(props){
try{
const response = _fetch(url, props)
}catch(err){
if(err instanceof HttpRequestError){
if (err.response?.status ===404){
// do something
return {}
}
}else{
throw err;
}
}
}