使用 fetch 和 ES6 promise 处理自定义错误的最简洁方法
Cleanest way to handle custom errors with fetch & ES6 promise
我正在尝试使用 fetch 和 ES6 promises 智能地处理来自我们 API 的 success/error 响应。
以下是我需要如何处理响应状态:
204: has no json response, but need to treat as success
406: should redirect to sign in
422: has json for error message
< 400 (but not 204): success, will have json
>= 400 (but not 422): error, will not have json
所以,我正在为如何干净利落地写这篇文章而苦恼。
我现在有一些不太出色的代码,看起来像这样:
fetch()
.then(response => checkStatus(response))
.then(parseJSON) //will throw for the 204
.then(data => notify('success', someMsg))
.catch(error => checkErrorStatus(error))
.then(parseJSON)
.then(data => notify('error', dataForMsg)
.catch(error => notify('error', someGenericErrorMsg)
但是使用 catch 两次似乎很奇怪,我还不知道如何处理那个 204。
另外,为了澄清 checkStatus
和 checkErrorStatus
做了类似的事情:
export function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response
} else {
let error = new Error(response.statusText)
error.response = response
throw error
}
}
function checkErrorStatus(error) {
if(error.response.status === 422) {
return error.response
} else {
let error = new Error(response.statusText)
error.response = response
throw error
}
}
有什么清理建议吗?
我想你可以很容易地写出来:
fetch(…).then(response => {
if (response.ok)
return response[response.status == 204 ? "text" : "json"]();
if (response.status == 422)
return response.json().then(err => { throw err; });
if (response.status == 406)
var error = new AuthentificationError(response.statusText); // or whatever
else
var error = new Error(response.statusText)
error.response = response
throw error;
})
根据 Bergi 的解决方案,您可以考虑使用相当简单的 ResponseHandler()
对象来机械化响应处理;
function ResponseHandler() {
this.handlers = [];
this.handlers[0] = function() {}; // a "do nothing" default handler
}
ResponseHandler.prototype.add = function(code, handler) {
this.handlers[code] = handler;
};
ResponseHandler.prototype.handle = function(response) {
var h = this.handlers,
s = response.status,
series = Math.floor(s / 100) * 100; // 100, 200, 300 etc
(h[s] || h[series] || h[0])(response); // sniff down the line for a specific/series/default handler, then execute it.
};
正在使用中:
// create an instance of ResponseHandler() and add some handlers :
var responseHandler = new ResponseHandler();
responseHandler.add(204, function(response) {...}); // specific handler
responseHandler.add(422, function(response) {...}); // specific handler
responseHandler.add(406, function(response) {...}); // specific handler
responseHandler.add(200, function(response) {...}); // 200 series default handler
responseHandler.add(400, function(response) {...}); // 400 series default handler
responseHandler.add(0, function(response) {...}); // your overall default handler
// then :
fetch(…).then(response => { responseHandler.handle(response); });
您会失去 Bergi 等硬编码解决方案的效率,但可能会受益于改进的可管理性和可重用性。
我正在尝试使用 fetch 和 ES6 promises 智能地处理来自我们 API 的 success/error 响应。
以下是我需要如何处理响应状态:
204: has no json response, but need to treat as success
406: should redirect to sign in
422: has json for error message
< 400 (but not 204): success, will have json
>= 400 (but not 422): error, will not have json
所以,我正在为如何干净利落地写这篇文章而苦恼。
我现在有一些不太出色的代码,看起来像这样:
fetch()
.then(response => checkStatus(response))
.then(parseJSON) //will throw for the 204
.then(data => notify('success', someMsg))
.catch(error => checkErrorStatus(error))
.then(parseJSON)
.then(data => notify('error', dataForMsg)
.catch(error => notify('error', someGenericErrorMsg)
但是使用 catch 两次似乎很奇怪,我还不知道如何处理那个 204。
另外,为了澄清 checkStatus
和 checkErrorStatus
做了类似的事情:
export function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response
} else {
let error = new Error(response.statusText)
error.response = response
throw error
}
}
function checkErrorStatus(error) {
if(error.response.status === 422) {
return error.response
} else {
let error = new Error(response.statusText)
error.response = response
throw error
}
}
有什么清理建议吗?
我想你可以很容易地写出来:
fetch(…).then(response => {
if (response.ok)
return response[response.status == 204 ? "text" : "json"]();
if (response.status == 422)
return response.json().then(err => { throw err; });
if (response.status == 406)
var error = new AuthentificationError(response.statusText); // or whatever
else
var error = new Error(response.statusText)
error.response = response
throw error;
})
根据 Bergi 的解决方案,您可以考虑使用相当简单的 ResponseHandler()
对象来机械化响应处理;
function ResponseHandler() {
this.handlers = [];
this.handlers[0] = function() {}; // a "do nothing" default handler
}
ResponseHandler.prototype.add = function(code, handler) {
this.handlers[code] = handler;
};
ResponseHandler.prototype.handle = function(response) {
var h = this.handlers,
s = response.status,
series = Math.floor(s / 100) * 100; // 100, 200, 300 etc
(h[s] || h[series] || h[0])(response); // sniff down the line for a specific/series/default handler, then execute it.
};
正在使用中:
// create an instance of ResponseHandler() and add some handlers :
var responseHandler = new ResponseHandler();
responseHandler.add(204, function(response) {...}); // specific handler
responseHandler.add(422, function(response) {...}); // specific handler
responseHandler.add(406, function(response) {...}); // specific handler
responseHandler.add(200, function(response) {...}); // 200 series default handler
responseHandler.add(400, function(response) {...}); // 400 series default handler
responseHandler.add(0, function(response) {...}); // your overall default handler
// then :
fetch(…).then(response => { responseHandler.handle(response); });
您会失去 Bergi 等硬编码解决方案的效率,但可能会受益于改进的可管理性和可重用性。