This question already has answers here:
Suppress Chrome 'Failed to load resource' messages in console
(3 answers)
Closed 3 years ago.
I am using React with axios and redux-promise. Axios does not appear to catch the 404 error, as below.
This is the code.
const url = FIVE_DAY_FORECAST_URL.replace("{0}", city);
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
try{
const request = axios.get(`${url}`).then(e => {
debugger; }).catch(
e => {
debugger;
return "ERROR"; // THIS FIRES, BUT DOES NOT STOP THE CONSOLE ERROR
});
debugger;
return {
type: FETCH_FIVE_DAY_FORECAST,
payload: request
};
} catch {
debugger;
console.log("Error!"); // DOES NOT HELP AS THE 404 IS NOT A JAVASCRIPT ERROR, IT'S A VALID SERVER RESPONSE
}
}
I am using a number of techniques to tr to catch the console error:
.then() ==> the code runs through this block, but the error has already happened, and has been written to the console!
.catch() ==> the code runs through this block if the interceptors are not configured i.e. comment out axios.interceptors.response.use... .
try...catch ==> no effect (does not catch the network response as this is not really a javascript error!)
When using try...catch with axios you explicitly have to state the error response like so
catch(error) {
console.log('[error]', error.response);
// use the error.response object for some logic here if you'd like
}
Otherwise it just returns the string value.
With that response object you can then utilize some logic to do something based on the particular error. More info can be found here https://github.com/axios/axios/issues/960
I hope this helps.
You are trying to catch the Promise.reject and wrapping it in a try...catch. Only one of this will work.
You can either catch a promise rejection or wrap the promise in a try...catch and throw a new error on promise rejection and catch it in catch block.
Try this code
const url = FIVE_DAY_FORECAST_URL.replace("{0}", city);
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
try {
const request = axios.get(`${url}`)
.then(
response => {
debugger;
})
.catch(
e => {
debugger;
throw e // throw the error and catch it
});
debugger;
return {
type: FETCH_FIVE_DAY_FORECAST,
payload: request
};
} catch {
debugger;
// Now you can catch the error in catch block
console.log("Error!");
}
// or you can't write async/await code
// make the the function is marked as `async`
try {
const response = await axios.get(`${url}`)
return {
type: FETCH_FIVE_DAY_FORECAST,
payload: response
};
} catch (e) {
console.error("Error happened during fetch");
console.error(e);
}
Related
I know this can be solved by writing all codes to async-await style, then can simply write let text = await res.text(); then try catch the JSON.parse(text) and then do decision.
But here I just want to know if there is any way we can achieve that in .then/.catch style.
Consider the below code:
async function test() {
try {
let n = await fetch("https://stackoverflow.com")
.then(res => {
return res.json()
})
.then(data => data.results.length)
.catch(e => {
console.error("Catch 2", e)
})
}
catch (e) {
console.error("Catch 3", e)
}
}
if we execute this function in the browser devtools(F12) with await test(), then there will be an error catch by the "Catch 2" clause. But in the error detail we can only see some logs like JSON parse error.
We cannot see the full text of the response body.
Is there any way that can get the text when the JSON parsing failed?
Your best bet is to look at the response in your devtools' network tab. That will show you the full response.
But if you want to do it in code, you can separate reading the response from parsing it by using the text method instead of the json method, then parsing the text yourself.
The parsing error may be down to the fact you aren't checking for HTTP success. As I noted on my old anemic blog here, fetch only rejects its promise on network errors, not HTTP errors (like 404, 500, etc.). To check for HTTP success, look at the ok or status properties.
Here's the minimal-changes version separating reading the response from parsing it, and checking for HTTP success before reading it at all:
async function test() {
try {
let n = await fetch("https://stackoverflow.com")
.then((res) => {
if (!res.ok) { // ***
throw new Error(`HTTP error ${res.status}`); // ***
} // ***
return res.text(); // ***
})
.then((text) => {
// *** you can look at `text` here in a debugger, or
// *** log it, save it, etc., before parsing below
// *** (which might throw an error)
try {
const data = JSON.parse(text); // ***
return data.results.length;
} catch (error) {
console.error("Parsing error", e);
console.error("Text we were parsing:", text);
}
})
.catch((e) => {
console.error("Catch 2", e);
});
// ...do something with `n`...
} catch (e) {
console.error("Catch 3", e);
}
}
But a couple of things there:
I wouldn't mix async/await with explicit promise callbacks like that.
With that and with your original code, errors will result in n receive the value undefined, because the catch handlers (and my new try/catch block in the then handler) don't return anything.
Instead:
async function test() {
try {
const res = await fetch("https://stackoverflow.com");
if (!res.ok) {
throw new Error(`HTTP error ${res.status}`);
}
const text = await res.text();
// *** you can look at `text` here in a debugger, or
// *** log it, save it, etc., before parsing below
// *** (which might throw an error)
try {
const data = JSON.parse(text);
const n = data.results.length;
// ...do something with `n`...
} catch (error) {
console.error("Parsing error", e);
console.error("Text we were parsing:", text);
}
} catch (e) {
console.error("Catch 3", e);
}
}
Or if you want to respond differently to the parsing error, wrap that bit in a try/catch, etc.
You shouldn't confuse the catch which catching errors in the fetch function itself - with the response errors
fetch("/developer.mozilla.org")
.then(res => {
if (!res.ok) {
console.log("there was an error also here") <= this code also runs
console.log("response is", res);
}
return res.json()
})
.then(data => data.results.length)
.catch(e => {
console.error("Catch 2", e);
})
In your case, you tried converting data -> JSON w/o success, it failed and dropped to the "catch" section.
but to inspect the response - you can dump it in the first section above where I added res.ok
I believe you could do something like this when using promise style Javascript:
const fetchDataPromise = () => {
fetch('https://stackoverflow.com').then((res) => {
res.json().then((jsonData) => {
console.log(jsonData)
}).catch((err) => {
console.error(err)
res.text().then((rawData) => {
console.log(rawData)
}).catch((err) => console.error(err))
})
})
}
Also more intuitive approach would be to use async/await (the trade-off is that you will have to do the API call again):
const fetchData = async () => {
try {
const res = await fetch('https://stackoverflow.com')
const jsonData = await res.json()
console.log(jsonData)
} catch (err) {
try {
console.error(err)
const res = await fetch('https://stackoverflow.com')
const rawData = await res.text()
console.log(rawData)
} catch (rawError) {
console.error(rawError)
}
}
}
I have the following code on python using flask
#bp.route("/test", methods=["GET"])
def test():
throw_error = True
if throw_error :
return jsonify(message="Throwing an error"), 405
return jsonify(message="Test message"), 200
on React I have a context setup with the following function
function testRequest(){
const response = axios.get('/api/test')
console.log(response)
}
I'm calling this function on a button click in another component by
async function handleButtonClick(e){
e.preventDefault();
try{
await testRequest();
}catch(error) { // DOESN'T EXECUTE??
console.error("Error occured")
setError("Error occurred in test method")
}
}
Why isn't the try catch, catching the 405 error?
You can only usefully await a promise. testRequest doesn't return a promise.
It triggers axios.get, assigns the promise to response, logs it, then returns undefined.
The try/catch doesn't touch the promise at all.
You could fix that with:
function testRequest(){
const response_promise = axios.get('/api/test')
console.log(response_promise)
return response_promise;
}
So the promise is being awaited inside the try/catch.
With below modification to your function, you will be able to catch error.
async function testRequest() {
const response = await axios.get('http://localhost:1337/sample/test');
return response;
}
async function handleButtonClick(e:any) {
e.preventDefault();
try {
await testRequest();
} catch (error) { // DOESN'T EXECUTE??
console.error("Error occured")
console.log(error.mes);
}
}
This question already has answers here:
Suppress Chrome 'Failed to load resource' messages in console
(3 answers)
Correct Try...Catch Syntax Using Async/Await
(6 answers)
Closed 3 years ago.
I'm a little bit confused about the right way to handle errors in an async function in javascript.
async function getWeatherAW(woeid) {
try {
const result = await fetch(`https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/${woeid}/`);
const data = await result.json();
const tomorrow = data.consolidated_weather[1];
return data;
} catch(error) {
console.log(`Error catch-Statement: ${error}`);
}
}
const wrongData = 3442;
getWeatherAW(wrongData)
.then(data => {
console.log(data);
})
.catch(error => {
console.log(`Error .catch()-Statement: ${error}`);
})
This code ended up giving this result. I'm curious about why even if the catch-statement is triggered a 404 error is printed out to the console..
Would it also be better to not return the result from the async function and instead proceed in the function? I mean the data in the then-block seems to be undefinded when an error occurs in first place.. and if I need to call the function more often, I don't always need to write the then and catch, right?
Thanks in advance!
The console prints a 404 message for all failed requests, regardless of whether the error is handled.
It's a debugging aid to show you that a request failed, not an indication that the failure wasn't handled.
the error says cannot read property '1' of undefined
async function getWeatherAW(woeid) {
try {
const result = await fetch(`https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/${woeid}/`);
const data = await result.json();
const tomorrow = data.consolidated_weather[1]; <----- this is undefined
return data;
} catch(error) {
console.log(`Error catch-Statement: ${error}`);
}
}
const wrongData = 3442;
getWeatherAW(wrongData)
.then(data => {
console.log(data);
})
.catch(error => {
console.log(`Error .catch()-Statement: ${error}`);
})
My guess is tomorrow is initializing before data has been initialized - or that data does not have key consolidate_weather
doing fetch.then() may get the result you want
let tomorrow;
return fetch(url).then((result) => {
const data = JSON.parse(result);
tomorrow = data.consolidated_weather[1];
return data;
}, (error) => {
console.log(`Error .catch()-Statement: ${error}`);
})
I'm calling an API that defines the statusCode from data instead of the response code:
{
data: {
statusCode: 422,
message: "User's not found"
},
status: 200
}
In my axios get request it's getting the status code from the status instead in data.
return axios.get(`${process.env.BASE_URL}/users`)
.then(response => {
console.log(response);
}).catch(err => {
console.log(err.message);
});
I'm getting the response but it should go to catch since it's 422.
How can I refer to the statusCode of the data response so that if it's not 200 it should go to catch statement
You can intercept the response, inspect the data and throw a custom error in this case:
// Add a response interceptor
axios.interceptors.response.use(function(response) {
if (response.data && response.data.statusCode && !(response.data.statusCode >= 200 && response.data.statusCode < 300)) throw new Error()
return response;
}, function(error) {
return Promise.reject(error);
});
// Make a GET request
axios.get(url)
.then((data) => {
console.log('data', data)
})
.catch((e) => {
console.log('error', e)
})
This way you configure your axios instance so you dont have to repeat yourself for every single request in your app
Also, you can override the status using following code. But since status validation has already executed, it will not throw errors on bad status codes
// Add a response interceptor
axios.interceptors.response.use(function(response) {
if (response.data && response.data.statusCode) response.status = response.data.statusCode
return response;
}, function(error) {
return Promise.reject(error);
});
You can handle with standard if statement inside the .then()
return axios.get(`${process.env.BASE_URL}/users`)
.then(response => {
if(response.data.statusCode===442){
...//custom error handling goes here
}else{
...//if statusCode is a success one
}
}).catch(err => {
console.log(err.message);
});
Check the response.data.statusCode value, if it is 442 then you should ideally throw an Error and let it be handled in the .catch callback.
return axios.get(`${process.env.BASE_URL}/users`)
.then(response => {
if(response.data.statusCode===442){
throw new Error(response.data.message); //using throw instead of Promise.reject() to break the control flow.
}else{
//return the data wrapped in promise
}
})
.catch((err) => {
console.log(err.message);
return Promise.reject(err.message);
});
My problem:
I have set up an interceptor to catch error codes in HTTP responses.
When the JWT expires, I have a code 401 coming back from the server. Here's my interceptor:
this.axios.interceptors.response.use(undefined, (error) => {
if (error.response.status === 401) {
this.$store.dispatch('auth/logout').then(() => {
this.$router.push({name: 'login'})
return Promise.reject(error)
})
}
})
My interceptor works fine, except the request that is being intercepted still resolves into the .then() part.
this.axios.get('/texts').then(function(){
// This is still being executed and generates javascript errors because the response doesn't contain the right data
})
From the axios documentation, I found out you can prevent this by calling
this.axios.get('/texts').then(function(){
// only on success
}).catch(function(){
// only on errors
}).then(function(){
// always executed
})
But this is pretty verbose and I don't want to do this on every request that my app makes.
My question is:
How do I prevent axios from executing the .then() callback when I have an error. Is it something I can do in the interceptor? Like event.stopPropagation() or something like that?
You can prevent the Axios Error by using the below set of code
this.axios.interceptors.response.use(undefined, (error) => {
if (error.response.status === 401) {
this.$store.dispatch('auth/logout').then(() => {
this.$router.push({name: 'login'})
return new Promise(() => { });
})
} else {
return Promise.reject(error)
}
})
Throw an exception from catch block to prevent 'then' block
this.axios.get('/texts').then(function(){
// only on success
}).catch(function(e){
// only on errors
throw e;
}).then(function(){
// Will not executed if there is an error but yes on success
})
Did you try catch in the end of the chain? You will get following
this.axios.get('/texts').then(function(){
// only on success
}).then(function(){
// only on success in previous then
}).catch(function(){
// executes on every error from `get` and from two previous `then`
})