I have an HTTP API that returns JSON data both on success and on failure.
我有一个HTTP API,它在成功和失败时返回JSON数据。
An example failure would look like this:
示例失败将如下所示:
~ ◆ http get http://localhost:5000/api/isbn/2266202022
HTTP/1.1 400 BAD REQUEST
Content-Length: 171
Content-Type: application/json
Server: TornadoServer/4.0
{
"message": "There was an issue with at least some of the supplied values.",
"payload": {
"isbn": "Could not find match for ISBN."
},
"type": "validation"
}
What I want to achieve in my JavaScript code is something like this:
我想在JavaScript代码中实现的是这样的:
fetch(url)
.then((resp) => {
if (resp.status >= 200 && resp.status < 300) {
return resp.json();
} else {
// This does not work, since the Promise returned by `json()` is never fulfilled
return Promise.reject(resp.json());
}
})
.catch((error) => {
// Do something with the error object
}
3 个解决方案
#1
78
// This does not work, since the Promise returned by `json()` is never fulfilled return Promise.reject(resp.json());
Well, the resp.json
promise will be fulfilled, only Promise.reject
doesn't wait for it and immediately rejects with a promise.
好吧,resp.json承诺将被实现,只有Promise.reject不会等待它并立即拒绝承诺。
I'll assume that you rather want to do the following:
我假设你宁愿做以下事情:
fetch(url).then((resp) => {
let json = resp.json(); // there's always a body
if (resp.status >= 200 && resp.status < 300) {
return json;
} else {
return json.then(Promise.reject.bind(Promise));
}
})
(or, written explicitly)
(或明确写)
return json.then(err => {throw err;});
#2
28
Here's a somewhat cleaner approach that relies on response.ok
and makes use of the underlying JSON data instead of the Promise
returned by .json()
.
这是一种更简洁的方法,依赖于response.ok并使用底层的JSON数据而不是.json()返回的Promise。
function myFetchWrapper(url) {
return fetch(url).then(response => {
return response.json().then(json => {
return response.ok ? json : Promise.reject(json);
});
});
}
// This should trigger the .then() with the JSON response,
// since the response is an HTTP 200.
myFetchWrapper('http://api.openweathermap.org/data/2.5/weather?q=*lyn,NY').then(console.log.bind(console));
// This should trigger the .catch() with the JSON response,
// since the response is an HTTP 400.
myFetchWrapper('https://content.googleapis.com/youtube/v3/search').catch(console.warn.bind(console));
#3
0
The solution above from Jeff Posnick is my favourite way of doing it, but the nesting is pretty ugly.
Jeff Posnick的上述解决方案是我最喜欢的方式,但嵌套非常难看。
With the newer async/await syntax we can do it in a more synchronous looking way, without the ugly nesting that can quickly become confusing.
使用更新的async / await语法,我们可以以更加同步的方式执行此操作,而不会使丑陋的嵌套很快变得混乱。
async function myFetchWrapper(url) {
const response = await fetch(url);
const json = await response.json();
return response.ok ? json : Promise.reject(json);
}
This works because, an async function always returns a promise and once we have the JSON we can then decide how to return it based on the response status (using response.ok).
这是有效的,因为异步函数总是返回一个promise,一旦我们有了JSON,我们就可以决定如何根据响应状态返回它(使用response.ok)。
You would error handle the same way as you would in Jeff's answer, or you could use try/catch, or even an error handling higher order function.
您将使用与Jeff的答案相同的方式处理错误,或者您可以使用try / catch,甚至是处理更高阶函数的错误。
const url = 'http://api.openweathermap.org/data/2.5/weather?q=*lyn,NY'
myFetchWrapper(url)
.then((res) => ...)
.catch((err) => ...);
#1
78
// This does not work, since the Promise returned by `json()` is never fulfilled return Promise.reject(resp.json());
Well, the resp.json
promise will be fulfilled, only Promise.reject
doesn't wait for it and immediately rejects with a promise.
好吧,resp.json承诺将被实现,只有Promise.reject不会等待它并立即拒绝承诺。
I'll assume that you rather want to do the following:
我假设你宁愿做以下事情:
fetch(url).then((resp) => {
let json = resp.json(); // there's always a body
if (resp.status >= 200 && resp.status < 300) {
return json;
} else {
return json.then(Promise.reject.bind(Promise));
}
})
(or, written explicitly)
(或明确写)
return json.then(err => {throw err;});
#2
28
Here's a somewhat cleaner approach that relies on response.ok
and makes use of the underlying JSON data instead of the Promise
returned by .json()
.
这是一种更简洁的方法,依赖于response.ok并使用底层的JSON数据而不是.json()返回的Promise。
function myFetchWrapper(url) {
return fetch(url).then(response => {
return response.json().then(json => {
return response.ok ? json : Promise.reject(json);
});
});
}
// This should trigger the .then() with the JSON response,
// since the response is an HTTP 200.
myFetchWrapper('http://api.openweathermap.org/data/2.5/weather?q=*lyn,NY').then(console.log.bind(console));
// This should trigger the .catch() with the JSON response,
// since the response is an HTTP 400.
myFetchWrapper('https://content.googleapis.com/youtube/v3/search').catch(console.warn.bind(console));
#3
0
The solution above from Jeff Posnick is my favourite way of doing it, but the nesting is pretty ugly.
Jeff Posnick的上述解决方案是我最喜欢的方式,但嵌套非常难看。
With the newer async/await syntax we can do it in a more synchronous looking way, without the ugly nesting that can quickly become confusing.
使用更新的async / await语法,我们可以以更加同步的方式执行此操作,而不会使丑陋的嵌套很快变得混乱。
async function myFetchWrapper(url) {
const response = await fetch(url);
const json = await response.json();
return response.ok ? json : Promise.reject(json);
}
This works because, an async function always returns a promise and once we have the JSON we can then decide how to return it based on the response status (using response.ok).
这是有效的,因为异步函数总是返回一个promise,一旦我们有了JSON,我们就可以决定如何根据响应状态返回它(使用response.ok)。
You would error handle the same way as you would in Jeff's answer, or you could use try/catch, or even an error handling higher order function.
您将使用与Jeff的答案相同的方式处理错误,或者您可以使用try / catch,甚至是处理更高阶函数的错误。
const url = 'http://api.openweathermap.org/data/2.5/weather?q=*lyn,NY'
myFetchWrapper(url)
.then((res) => ...)
.catch((err) => ...);