2015-04-06 64 views
43

我有一个HTTP API,在成功和失败时都返回JSON数据。提取:拒绝承诺与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 
    } 
+0

你的意思是'json'方法返回一个'Promise'? – thefourtheye

+2

是的,根据工作组的fetch规范:https://fetch.spec.whatwg.org/#concept-body-consume-body – jbaiter

回答

71
// This does not work, since the Promise returned by `json()` is never fulfilled 
return Promise.reject(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;}); 
+0

谢谢,(几乎)确实有效!我不得不在一个匿名函数中包装Promise.reject,否则我会得到一个'undefined不是函数'的错误,但是这个小改动可以工作:-) – jbaiter

+0

呃,你是否懒惰地加载Promise填充?原生的'Promise.reject'不应该是'undefined'。 – Bergi

+0

Shim在应用程序启动时加载,所以不应该延迟加载。我也可以从调试器访问'Promise.reject'。下面是完整的跟踪:'TypeError:undefined不是函数{stack:“TypeError:undefined不是函数在reject(native)”,message:“undefined不是函数”} – jbaiter

26

下面是依靠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=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));

+1

啊,'.ok'看起来很有趣,但我没有看到“底层JSON数据”的用法更清晰,毕竟你可以简化为'fetch(url).then(response = > response.ok?response.json():response.json()。then(err => Promise.reject(err)))' – Bergi

+0

我的意思是代替'let json = resp.json();' json'是一个'Promise',它可以更简单地先解决'Promise',然后利用解析后的数据。两种方法都有效。 –

+0

试图拒绝嵌套的承诺,但不太清楚如何。原来,这只是对静态“拒绝”方法的调用。在我看来,答案要比接受的答案好得多。 – Andris