fetch:使用JSON错误对象拒绝承诺

jba*_*ter 56 javascript promise es6-promise fetch-api

我有一个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"
}
Run Code Online (Sandbox Code Playgroud)

我想在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
   }
Run Code Online (Sandbox Code Playgroud)

Ber*_*rgi 91

 // This does not work, since the Promise returned by `json()` is never fulfilled
return Promise.reject(resp.json());
Run Code Online (Sandbox Code Playgroud)

好吧,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));
  }
})
Run Code Online (Sandbox Code Playgroud)

(或明确写)

    return json.then(err => {throw err;});
Run Code Online (Sandbox Code Playgroud)

  • 在拒绝?啊,它需要是`.then(Promise.reject.bind(Promise))`. (2认同)

Jef*_*ick 38

这是一种更简洁的方法,依赖于response.ok并使用底层的JSON数据而不是Promise返回的.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));
Run Code Online (Sandbox Code Playgroud)


tom*_*hes 5

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);
}
Run Code Online (Sandbox Code Playgroud)

之所以可行因为异步函数总是返回一个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);
}
Run Code Online (Sandbox Code Playgroud)

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