fetch:拒绝带有 JSON 错误对象的Promise

IT技术 javascript promise es6-promise fetch-api
2021-01-30 00:49:27

我有一个 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
   }
4个回答
 // This does not work, since the Promise returned by `json()` is never fulfilled
return Promise.reject(resp.json());

那么,resp.jsonpromise被实现,只是Promise.reject不等待它并立即拒绝一个 promise

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

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;});
垫片在应用程序启动时加载,因此不应延迟加载。我也可以Promise.reject从调试器正常访问这是完整的跟踪:TypeError: undefined is not a function {stack: "TypeError: undefined is not a function↵ at reject (native)", message: "undefined is not a function"}
2021-03-15 00:49:27
在拒绝?啊,它必须是.then(Promise.reject.bind(Promise))
2021-03-17 00:49:27
@torazaburo:不,json这里是一个promise,我们不想用promise 拒绝,而是用它的结果值拒绝。
2021-03-26 00:49:27
谢谢,那(几乎)确实有效!我不得不将 Promise.reject 包装在一个匿名函数中,否则我会得到一个undefined is not a function错误,但是通过这个小小的改变它可以工作:-)
2021-04-02 00:49:27
呃,你在懒加载 Promise 垫片吗?本机Promise.reject永远不应该是undefined
2021-04-11 00:49:27

下面是依赖于一定程度上更简洁的方法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));

我的意思是,而不是let json = resp.json();where jsonis a Promise,它可以更简单地解析第Promise一个,然后使用它解析的数据。这两种方法都有效。
2021-03-23 00:49:27
啊,.ok看起来很有趣。然而,我认为“底层 JSON 数据”的使用并不干净。毕竟,您可以将其简化为fetch(url).then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
2021-04-04 00:49:27
试图拒绝嵌套的Promise,但不太确定如何拒绝。原来它只是对静态“拒绝”方法的调用。在我看来,这是一个比公认的更好的答案。
2021-04-13 00:49:27

上面来自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,一个错误处理高阶函数,或者进行一些修改以防止Promise拒绝,您可以使用我最喜欢的技术来确保错误处理是作为开发人员体验的一部分强制执行

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 不是网络错误。

我在MDN找到了我的解决方案

function fetchAndDecode(url) {
  return fetch(url).then(response => {
    if(!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    } else {
      return response.blob();
    }
  })
}

let coffee = fetchAndDecode('coffee.jpg');
let tea = fetchAndDecode('tea.jpg');

Promise.any([coffee, tea]).then(value => {
  let objectURL = URL.createObjectURL(value);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e => {
  console.log(e.message);
});