获取:如果状态不正常,拒绝承诺并捕获错误?
Posted
技术标签:
【中文标题】获取:如果状态不正常,拒绝承诺并捕获错误?【英文标题】:Fetch: reject promise and catch the error if status is not OK? 【发布时间】:2016-11-09 04:42:34 【问题描述】:这就是我要做的:
import 'whatwg-fetch';
function fetchVehicle(id)
return dispatch =>
return dispatch(
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/$id/`)
.then(status)
.then(res => res.json())
.catch(error =>
throw(error);
)
);
;
function status(res)
if (!res.ok)
return Promise.reject()
return res;
编辑:承诺不会被拒绝,这就是我想要弄清楚的。
我在 Redux 中使用这个 fetch polyfill 和 redux-promise-middleware。
【问题讨论】:
您在catch
中抛出异常,但不要在catch
它。
它确实到达catch
(它捕获了它所连接的整个链中的所有拒绝),但catch
回调不处理任何事情 -它只会重新抛出错误。将throw
替换为console.error
左右。
浏览器死机?这绝对不应该发生。
谢谢大家,我对此有点陌生,冻结是由其他原因引起的。我认为这对我来说是个问题,因为polyfill 将 404 视为成功响应。我在拒绝承诺时遇到了一些麻烦,一旦我发现它应该没问题。
更好的东西 github.com/github/fetch/issues/203#issuecomment-143347675
【参考方案1】:
function handleErrors(response)
if (!response.ok)
throw Error(response.statusText);
return response;
fetch("https://example.com/api/users")
.then(handleErrors)
.then(response => console.log("ok") )
.catch(error => console.log(error) );
【讨论】:
【参考方案2】:我对任何建议的解决方案都不满意,所以我尝试了Fetch API 以找到一种方法来处理成功响应和错误响应。
计划是在这两种情况下都获得status: XXX, message: 'a message'
格式。
注意:成功响应可以包含空正文。在这种情况下,我们回退并使用Response.status
和Response.statusText
来填充结果响应对象。
fetch(url)
.then(handleResponse)
.then((responseJson) =>
// Do something with the response
)
.catch((error) =>
console.log(error)
);
export const handleResponse = (res) =>
if (!res.ok)
return res
.text()
.then(result => JSON.parse(result))
.then(result => Promise.reject( status: result.status, message: result.message ));
return res
.json()
.then(result => Promise.resolve(result))
.catch(() => Promise.resolve( status: res.status, message: res.statusText ));
;
【讨论】:
【参考方案3】:希望这对我有所帮助抛出错误不起作用
function handleErrors(response)
if (!response.ok)
return new Promise((resolve, reject) =>
setTimeout(() =>
reject(
status: response.status,
statusText: response.statusText,
);
, 0);
);
return response.json();
function clickHandler(event)
const textInput = input.value;
let output;
fetch(`$URL$encodeURI(textInput)`)
.then(handleErrors)
.then((json) =>
output = json.contents.translated;
console.log(output);
outputDiv.innerhtml = "<p>" + output + "</p>";
)
.catch((error) => alert(error.statusText));
【讨论】:
【参考方案4】:@fny 的答案(已接受的答案)对我不起作用。 throw new Error()
没有被 .catch
接收。我的解决方案是将fetch
包装成一个构建新承诺的函数:
function my_fetch(url, args)
return new Promise((resolve, reject) =>
fetch(url, args)
.then((response) =>
response.text().then((body) =>
if (response.ok)
resolve(body)
else
reject(body)
)
)
.catch((error) => reject(error) )
)
现在每个错误和不正常的返回都将被.catch
方法拾取:
my_fetch(url, args)
.then((response) =>
// Do something with the response
)
.catch((error) =>
// Do something with the error
)
【讨论】:
【参考方案5】:以下login with username and password
示例展示了如何:
-
检查
response.ok
reject
如果不OK,而不是抛出错误
进一步处理来自服务器的任何错误提示,例如验证问题
login()
const url = "https://example.com/api/users/login";
const headers =
Accept: "application/json",
"Content-Type": "application/json",
;
fetch(url,
method: "POST",
headers,
body: JSON.stringify(
email: this.username,
password: this.password,
),
)
.then((response) =>
// 1. check response.ok
if (response.ok)
return response.json();
return Promise.reject(response); // 2. reject instead of throw
)
.then((json) =>
// all good, token is ready
this.store.commit("token", json.access_token);
)
.catch((response) =>
console.log(response.status, response.statusText);
// 3. get error messages, if any
response.json().then((json: any) =>
console.log(json);
)
);
,
【讨论】:
这对我有用!似乎 throw 不像在其他语言中习惯的那样工作。简单地返回 Promise.reject() 将通过所有后续的 .thens 并降落在下一个捕获中【参考方案6】:2021 TypeScript 答案
我所做的是编写一个采用泛型的fetch
包装器,如果response
是ok
,它将自动.json()
并键入断言结果,否则包装器将抛出response
export const fetcher = async <T>(input: RequestInfo, init?: RequestInit) =>
const response = await fetch(input, init);
if (!response.ok)
throw response;
return response.json() as Promise<T>;
;
然后我会捕捉错误并检查它们是否是instanceof
Response
。这样 TypeScript 就知道 error
具有 Response
属性,例如 status
statusText
body
headers
等,我可以为每个 4xx
5xx
状态代码应用自定义消息。
try
return await fetcher<LoginResponse>("http://localhost:8080/login",
method: "POST",
headers:
Accept: "application/json",
"Content-Type": "application/json",
,
body: JSON.stringify( email: "user@example.com", password: "passw0rd" ),
);
catch (error)
if (error instanceof Response)
switch (error.status)
case 401:
throw new Error("Invalid login credentials");
/* ... */
default:
throw new Error(`Unknown server error occured: $error.statusText`);
throw new Error(`Something went wrong: $error.message || error`);
如果发生网络错误之类的事情,它可以在instanceof
Response
检查之外通过更通用的消息被捕获,即
throw new Error(`Something went wrong: $error.message || error`);
【讨论】:
【参考方案7】:Fetch 承诺仅在发生网络错误时以 TypeError 拒绝。由于 4xx 和 5xx 响应不是网络错误,因此没有什么可捕获的。您需要自己抛出错误才能使用Promise#catch
。
fetch Response 方便地提供ok
,它告诉您请求是否成功。像这样的东西应该可以解决问题:
fetch(url).then((response) =>
if (response.ok)
return response.json();
else
throw new Error('Something went wrong');
)
.then((responseJson) =>
// Do something with the response
)
.catch((error) =>
console.log(error)
);
【讨论】:
我没有找到“好的”属性,而是检查了 response.status === 200。 为什么我不能从我的代码中看出为什么抛出了 TypeError?在控制台中,我看到一种情况是“net::ERR_CONNECTION_TIMED_OUT”,但在另一种情况下是“(blocked:mixed-content)”,我不想对两者都做出同样的回应。 此解决方案是否会停止在控制台中出现错误,例如 401 无效请求? 我们如何在没有网络连接或服务器响应时返回自定义响应,例如503 Service Temp. Unavailable
如果被拒绝的承诺的结果是 TypeError
?
如何读取 JSON 文件?我从 BE 发送了我在 catch 块中需要的其他数据【参考方案8】:
对我来说, fny 的答案真的得到了一切。由于 fetch 没有抛出错误,我们需要自己抛出/处理错误。 使用 async/await 发布我的解决方案。我认为它更加简洁和可读
解决方案一:不抛出错误,自己处理错误
async _fetch(request)
const fetchResult = await fetch(request); //Making the req
const result = await fetchResult.json(); // parsing the response
if (fetchResult.ok)
return result; // return success object
const responseError =
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
;
const error = new Error();
error.info = responseError;
return (error);
如果我们得到一个错误,我们正在构建一个错误对象,普通的 JS 对象并返回它,缺点是我们需要在外面处理它。 使用方法:
const userSaved = await apiCall(data); // calling fetch
if (userSaved instanceof Error)
debug.log('Failed saving user', userSaved); // handle error
return;
debug.log('Success saving user', userSaved); // handle success
解决方案 2:抛出错误,使用 try/catch
async _fetch(request)
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok)
return result;
const responseError =
type: 'Error',
message: result.message || 'Something went wrong',
data: result.data || '',
code: result.code || '',
;
let error = new Error();
error = ...error, ...responseError ;
throw (error);
这里我们抛出了我们创建的错误,因为 Error ctor 只批准字符串,我创建了普通的 Error js 对象,用途将是:
try
const userSaved = await apiCall(data); // calling fetch
debug.log('Success saving user', userSaved); // handle success
catch (e)
debug.log('Failed saving user', userSaved); // handle error
解决方案 3:使用客户错误
async _fetch(request)
const fetchResult = await fetch(request);
const result = await fetchResult.json();
if (fetchResult.ok)
return result;
throw new ClassError(result.message, result.data, result.code);
还有:
class ClassError extends Error
constructor(message = 'Something went wrong', data = '', code = '')
super();
this.message = message;
this.data = data;
this.code = code;
希望对您有所帮助。
【讨论】:
【参考方案9】:我刚刚检查了响应对象的状态:
$promise.then( function successCallback(response)
console.log(response);
if (response.status === 200) ...
);
【讨论】:
不够好,201 (Resource Created) 也是有效响应,实际上 200-299 范围内的任何内容都不是客户端错误。【参考方案10】:感谢大家的帮助,拒绝.catch()
中的promise解决了我的问题:
export function fetchVehicle(id)
return dispatch =>
return dispatch(
type: 'FETCH_VEHICLE',
payload: fetch(`http://swapi.co/api/vehicles/$id/`)
.then(status)
.then(res => res.json())
.catch(error =>
return Promise.reject()
)
);
;
function status(res)
if (!res.ok)
throw new Error(res.statusText);
return res;
【讨论】:
你也可以从你的状态函数中拒绝承诺:function status(res) if (!res.ok) return Promise.reject(res.statusText); return res;
或者实际上你可以用你的端点给出的消息拒绝承诺。
或者实际上,如果您 jsonfy 该响应,您可以使用端点给出的消息拒绝该承诺,然后使用您从 jsonfied 响应中选择的属性返回一个 Promise denied。
.catch(error => return Promise.reject() )
似乎毫无意义。为什么要压制有用的error
而用undefined
拒绝呢?
@Vivek 或者您也可以只使用throw undefined;
。我抱怨的不是拒绝,而是忽略了error
。不过,可能整个事情都应该省略。
@Vivek 这可能更有意义,但这不是他们所做的。此外,使用undefined
代替带有正确消息的错误仍然是一种不好的做法。以上是关于获取:如果状态不正常,拒绝承诺并捕获错误?的主要内容,如果未能解决你的问题,请参考以下文章
vue-resource:在拦截 ajax 错误时捕获“未捕获(在承诺中)”
Youtube API未捕获(在承诺中)错误:请求失败,状态码为403
React axios api调用错误:未捕获(在承诺中)TypeError:setTempFetch不是函数