fetch:拒绝带有 JSON 错误对象的承诺
Posted
技术标签:
【中文标题】fetch:拒绝带有 JSON 错误对象的承诺【英文标题】:fetch: Reject promise with JSON error object 【发布时间】:2015-06-10 23:28:00 【问题描述】:我有一个 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
【问题讨论】:
你的意思是json
方法返回一个Promise
?
是的,根据工作组的fetch
规范:fetch.spec.whatwg.org/#concept-body-consume-body
【参考方案1】:
// 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;);
【讨论】:
谢谢,这(几乎)确实有效!我必须将 Promise.reject 包装在一个匿名函数中,否则我会得到一个undefined is not a function
错误,但只要稍作改动,它就可以工作:-)
呃,你是在延迟加载 Promise shim 吗?原生的Promise.reject
不应该是undefined
。
shim 在应用程序启动时加载,因此不应延迟加载。我也可以从调试器访问Promise.reject
。这是完整的跟踪:TypeError: undefined is not a function stack: "TypeError: undefined is not a function↵ at reject (native)", message: "undefined is not a function"
拒绝?啊,应该是.then(Promise.reject.bind(Promise))
。
@torazaburo:不,json
在这里是一个承诺,我们不想拒绝承诺,而是拒绝它的结果值。【参考方案2】:
这是一种更简洁的方法,它依赖于 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=***lyn,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));
【讨论】:
啊,.ok
看起来很有趣。然而,我没有看到“底层 JSON 数据”的使用更干净。毕竟,您可以将其简化为 fetch(url).then(response => response.ok ? response.json() : response.json().then(err => Promise.reject(err)))
我的意思是,与 let json = resp.json();
相比,json
是 Promise
,先解析 Promise
然后使用解析的数据可能更简单。两种方法都有效。
试图拒绝嵌套的承诺,但不太确定如何。原来这只是对静态“拒绝”方法的调用。在我看来,这是一个比公认的更好的答案。【参考方案3】:
上面来自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);
这是因为 an async function always returns a promise 并且一旦我们有了 JSON,我们就可以根据响应状态决定如何返回它(使用 response.ok)。
您会以与 Jeff 的回答相同的方式处理错误,但是您也可以使用 try/catch、error handling higher order function,或者进行一些修改以防止承诺被拒绝,您可以使用我最喜欢的技术来确保 @987654325 @。
const url = 'http://api.openweathermap.org/data/2.5/weather?q=***lyn,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 - Checking that the fetch was successful,了解为什么我们必须这样做,本质上,获取请求只会因网络错误而被拒绝,获得 404 并不是网络错误。
【讨论】:
【参考方案4】:我在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);
);
【讨论】:
【参考方案5】:也许这个选项可能是有效的
new Promise((resolve, reject) =>
fetch(url)
.then(async (response) =>
const data = await response.json();
return statusCode: response.status, body: data ;
)
.then((response) =>
if (response.statusCode >= 200 && response.statusCode < 300)
resolve(response.body);
else
reject(response.body);
)
);
【讨论】:
正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center。以上是关于fetch:拒绝带有 JSON 错误对象的承诺的主要内容,如果未能解决你的问题,请参考以下文章
Javascript Fetch API - 如何将输出作为对象保存到变量(不是承诺)
*可能的未处理承诺拒绝(id:0):类型错误:未定义不是对象(评估'result.cancelled')云图像上传
.catch() 甚至通过 fetch() 从另一个承诺中捕获所有错误
使用React Native Fetch中的对象响应时未处理的Promise Rejection
未处理的承诺拒绝:未定义不是对象(评估 _expoLocation.requestForegroundPermissionsAsync)