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

Javascript fetch:使用JSON错误对象拒绝承诺,javascript,promise,es6-promise,fetch-api,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

我有一个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"
}
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
   }
我希望在JavaScript代码中实现以下目标:

~ ◆ 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"
}
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
   }
fetch(url)
。然后((resp)=>{
如果(响应状态>=200&响应状态<300){
返回resp.json();
}否则{
//这是行不通的,因为“json()”返回的承诺从未兑现
return Promise.reject(resp.json());
}
})
.catch((错误)=>{
//对错误对象执行某些操作
}
好的,
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));
  }
})

这里有一种更简洁的方法,它依赖并使用底层JSON数据,而不是
.JSON()
返回的
Promise

函数myFetchWrapper(url){
返回获取(url)。然后(响应=>{
返回response.json().then(json=>{
return response.ok?json:Promise.reject(json);
});
});
}
//这将触发带有JSON响应的.then(),
//因为响应是HTTP 200。
myFetchWrapper('http://api.openweathermap.org/data/2.5/weather?q=Brooklyn然后(console.log.bind(console));
//这将触发带有JSON响应的.catch(),
//因为响应是HTTP 400。
myFetchWrapper('https://content.googleapis.com/youtube/v3/search“).catch(console.warn.bind(console));
上面的解决方案是我最喜欢的方法,但是嵌套非常难看

使用较新的async/await语法,我们可以以一种更同步的方式来完成,而不会出现可能很快变得混乱的丑陋嵌套

async function myFetchWrapper(url) {
  const response = await fetch(url);
  const json = await response.json();
  return response.ok ? json : Promise.reject(json);
}
这是因为,一旦有了JSON,我们就可以根据响应状态决定如何返回它(使用)

您可以使用与Jeff回答中相同的方法处理错误,但是您也可以使用try/catch、an或进行一些修改以防止拒绝承诺。您可以使用我最喜欢的技术来确保


同样值得一读的是,为什么我们必须这样做,本质上一个获取请求只会因为网络错误而被拒绝,获取一个404不是一个网络错误。

你的意思是
json
方法返回一个
Promise
?是的,根据工作组的
fetch
规范:谢谢,这(差不多)成功了!我必须在匿名函数中包装Promise.reject,否则我会得到一个
未定义的函数不是一个函数
错误,但是有了这个小改动它就可以工作了:-)嗯,你是不是懒得加载Promise?本机
Promise.reject
永远不应该是
undefined
。垫片是在应用程序启动时加载的,因此不应该延迟加载。我可以从调试器访问
Promise.reject
也可以。以下是完整的跟踪:
TypeError:undefined不是函数{stack:“TypeError:undefined不是函数↵    在拒绝时(本机)”,消息:“未定义不是函数”}
在拒绝时?啊,它需要是
。然后(Promise.reject.bind(Promise))
@torazaburo:No,
json
在这里是一个承诺,我们不想用承诺来拒绝,而是用它的结果值。啊,
。好的
看起来很有趣。然而,我不认为“底层JSON数据”的用法更干净。毕竟,您可以将其简化为
fetch(url)。然后(response=>response.ok?response.json():response.json()。然后(err=>Promise.reject(err))
我的意思是让json=resp.json()代替
如果
json
是一个
Promise
,那么首先解析
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);
}