javascript-提取:拒绝带有JSON错误obj的Promise

我有一个HTTP API,它在成功和失败时都返回JSON数据。

失败示例如下所示:

~ ◆ 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"
}

我想要在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
   }
jbaiter asked 2019-11-08T10:57:22Z
3个解决方案
89 votes
resp.json

好吧,resp.json的诺言将被兑现,只有Promise.reject不等待它,而是立即兑现诺言。

我假设您宁愿执行以下操作:

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));
  }
})

(或明确写出)

    return json.then(err => {throw err;});
Bergi answered 2019-11-08T10:58:01Z
37 votes

这是一种较为干净的方法,该方法依赖于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=Brooklyn,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));并使用基础JSON数据,而不是.json()返回的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=Brooklyn,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));

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=Brooklyn,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));

Jeff Posnick answered 2019-11-08T10:58:31Z
5 votes

Jeff Posnick的上述解决方案是我最喜欢的解决方案,但是嵌套非常难看。

使用更新的async / await语法,我们可以以更同步的方式进行操作,而不会出现令人费解的丑陋嵌套。

async function myFetchWrapper(url) {
  const response = await fetch(url);
  const json = await response.json();
  return response.ok ? json : Promise.reject(json);
}

之所以可行,是因为异步函数总是返回一个promise,一旦有了JSON,我们就可以根据响应状态(使用response.ok)决定如何返回它。

您将以与Jeff的答案相同的方式处理错误,或者可以使用try / catch甚至处理高阶函数的错误。

const url = 'http://api.openweathermap.org/data/2.5/weather?q=Brooklyn,NY'

// Example with Promises
myFetchWrapper(url)
  .then((res) => ...)
  .catch((err) => ...);

// Example with try/catch (presuming wrapped in an async function)
try {
  const data = await myFetchWrapper(url);
  ...
} catch (err) {
  throw new Error(err.message);
}

还值得一读MDN-检查是否成功获取了我们为什么要这样做的信息,本质上来说,获取请求只会拒绝网络错误,获取404并不是网络错误。

tomhughes answered 2019-11-08T10:59:24Z
translate from https://stackoverflow.com:/questions/29473426/fetch-reject-promise-with-json-error-object