[英]Fetch: reject promise and catch the error if status is not OK?
這是我要做的:
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;
}
編輯:promise 沒有被拒絕,這就是我想要弄清楚的。
我在 Redux 中使用這個fetch polyfill 和redux-promise-middleware 。
Fetch Promise 僅在發生網絡錯誤時以 TypeError 拒絕。 由於 4xx 和 5xx 響應不是網絡錯誤,因此沒有什么可捕獲的。 您需要自己拋出錯誤才能使用Promise#catch
。
一個fetch Response方便地提供一個ok
,它告訴你請求是否成功。 這樣的事情應該可以解決問題:
fetch(url).then((response) => {
if (response.ok) {
return response.json();
}
throw new Error('Something went wrong');
})
.then((responseJson) => {
// Do something with the response
})
.catch((error) => {
console.log(error)
});
感謝大家的幫助,拒絕.catch()
中的承諾解決了我的問題:
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;
}
對我來說,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;
}
}
希望它有所幫助。
以下login with username and password
示例顯示了如何:
response.ok
reject
,而不是拋出錯誤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);
})
});
},
我所做的是編寫一個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}`);
@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) })
})
}
現在每個錯誤和非 ok 返回都將被.catch
方法拾取:
my_fetch(url, args)
.then((response) => {
// Do something with the response
})
.catch((error) => {
// Do something with the error
})
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) );
我剛剛檢查了響應對象的狀態:
$promise.then( function successCallback(response) {
console.log(response);
if (response.status === 200) { ... }
});
我對任何建議的解決方案都不滿意,所以我使用了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 }));
};
希望這對我有幫助throw Error is not working
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));
}
與大多數答案產生共鳴的另一個(較短的)版本:
fetch(url)
.then(response => response.ok ? response.json() : Promise.reject(response))
.then(json => doStuff(json)) //all good
//next line is optional
.catch(response => handleError(response)) //handle error
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.