Fetch API how to get response body in catch? - javascript

I got the response from server like this:
Request URL:http://api.bfexchange.net/wallet/balance
Request Method:GET
Status Code:504 Gateway Time-out
Remote Address:52.78.140.154:80
Referrer Policy:no-referrer-when-downgrade
But printing err in catch of fetch API just returns Error object.
fetch(...)
.then(...)
.catch((err) => {
console.dir(err);
});
It prints this(from Google Chrome):
TypeError: Failed to fetch
message: "Failed to fetch"
stack: "TypeError: Failed to fetch"
__proto__: Error
index.js:82
I want to get status code to proper error handling, like server is not responding like something.
Is there a way to get response data in this case? Else, what alternatives can I attempt?
Any advice will very appreciate it!

If the server uses CORS you will get the 5xx response, but it won't be as a rejection; the promise will be resolved with the response. If the server does not use CORS, you won't ever see a response and the promise will always be rejected (unless you use "no-cors", in which case you can get an opaque response that is useful in some service worker scenarios).

Related

How can a JS script capture the details of a CORS request failure? [duplicate]

Is it possible to get the error code of a failed preflight request so that I can print a meaningful error message? (Or is there a habit of printing a static error for all failed preflight requests no matter the code?)
Clearly, the status code 401 is printed to the console, but the error handler or a .catch() statement only receive the error object thrown.
If I remove the header that triggers the preflight, I get to handle the response myself and I can extract the status code.
// also note that the returned code 401 in first screenshot is wrong. But that's another question..
No, it isn't.
If the status code of the preflight response is not 200, then the Same Origin Policy will prevent any information about the response from being extracted from it.
I've just finished setting up a web API to always return 200 OK status for OPTIONS requests for this reason.
Unfortunately not. All fetch returns is a TypeError with message "Failed to fetch".
> fetch('https://stackexchange.com/404').then(x => console.info(x), error => console.error(error))
× TypeError: Failed to fetch
I tried to manually send another preflight-request and grab the response code of that.
> fetch('https://stackexchange.com/404', { method: 'OPTIONS' }).then(x => console.info(x), error => console.error(error))
× TypeError: Failed to fetch
But that just triggers another preflight and still doesn't let me at the actual failed request.

Is 4xx and 5xx network errors?

I have a node server that basically reads a component from a specific path, executes the code, and returns the data to the other server.
Sometimes during the code execution of the component, I get a 403 response.
Error:
ApolloError: Response not successful: Received status code 403
I'm using .catch() to catch the 403 response but it's not helping and there are frequent pod crashes due to the 403.
I have checked this StackOverflow answer - Fetch: reject promise and catch the error if status is not OK?
It mentions that
Since 4xx and 5xx responses aren't network errors, there's nothing to catch
Is this correct?
If the above statement is true, can it be handled like the below:
app.use((req,res) => {
res.status(403).send('');
})
Is 4xx and 5xx network errors?
No, they're HTTP error responses, successfully transferred from the server to the client via the network.
I'm using .catch() to catch the 403 response
I assume you mean with fetch given the question you linked to. This is a common issue (a footgun in my view) with using the fetch API. fetch only rejects its promise on network errors, not HTTP errors. So, it will reject its promise if it can't contact the server. It won't if it successfully contacts the server and receives an HTTP error response.
The answers to the question you link (such as this one) and my linked blog post above describe how to handle this using a common path for network and HTTP errors: When you first get the Response object, check its ok property and throw if it's not true, then handle rejection in a common rejection handler.
But reiterating in case those resources disappear (unlikely, but answers are supposed to be self-contained), using JSON as an example, I'll usually have something like this in my codebase on a project:
async function fetchJSON(...args) {
const response = await fetch(...args);
if (!response.ok) {
// Network was fine, but there was an HTTP error
throw new Error(`HTTP error ${response.status}`);
}
return await response.json();
}
I do that because the vast, vast, vast majority of the time, the code doing the fetch doesn't care whether there was a network error or an HTTP error, it just cares that the fetch (and associated JSON parsing) did or didn't work.

XMLHttpRequest Send() throws error despite onreadystatechange handler

I am using XmlhttpRequest to send a POST requests on localhost and chrome developer tools console and network to verify the requests.
I have two methods:
Method1 send the post requests.
Requesthandler handles the requests response.
When the request is successful (200) it does not throw an error and the request handler outputs a message on console. But when the request is unsuccessful. My console throws an error despite the request handler.
For example, If I purposely set the wrong url adress. I expect a 404 status Not Found exception and the request handler to output a message on console. Despite it happening, it still goes ahead and throws on the error on Send() Method.
Why xmlhttprequest.send() throws errors despite handling responses on the onreadystatechange event?
Method1(Sends Requests)
RequestHandler(Handles responses)
Console Message:
Thrown Error:

fetch from API - specific API errors vs general HTTP errors

I am using fetch() to get results from an API. As I understand it, there's 2 different types of errors:
an error that my API returns specifically: for example "invalid authentication token"
more generic HTTP errors: for example - network timeout or connectivity was interrupted.
Is there a way to determine the nature of the issue, in such a way that I can retry an API command when it makes sense (like poor network connectivity), but not retry it if it's just going to give the same result as the previous time (like an invalid token error)
Is there a way to determine the nature of the issue, in such a way that I can retry an API command when it makes sense (like poor network connectivity), but not retry it if it's just going to give the same result as the previous time (like an invalid token error)
fetch() only throws if there was some error with recieving the data. If your server responded with an error status, you'd have to check that in the then() block.
#Thomas Thanks! So in general if i enter my catch() block of the fetch(), I can treat that as a network issue?
Think the other way around. If you land in the then() part, your server has responded successfully; wether you like that response (200) or not (404).
If you land in the catch() part of the fetch(), something went wrong with the request and a network error is one of the more likely reasons. An invalid url, like "//", would be another reason to throw.

In what cases an HTTP request is made but no response is received?

I am using axios to make an HTTP request and getting an error. This is a snippet from axios docs talking about handling of errors.
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
In my case, error.request is coming out to be true, which means (according to the docs) a request was made but no response was received. My question is, what could be causing it? what are the cases when a request is made but no response is received?
Thanks
It often happens for two reasons:
1. OPTIONS request is failed
Top reasons in my practice:
server checks authorisation on OPTIONS request
server sends wrong headers
server make some redirect
More about OPTIONS requests
2. Network problems
I saw this a lot in corporate networks with a lot of firewalls. If there is no way to fix network issues then aggressive retries usually helps.
if (err && err.request && !err.response && navigator.onLine !== false) {
// try again ...
}
The only way you get a .catch() if no response was returned from the API endpoint is if Axios (or the host system that Axios is running on) implemented a timeout and no response was received within that timeout period. So, without seeing more info on the specific request you're making and the specific API, it appears that there are two possibilities here:
Your API endpoint has a bug and does not send a response in some circumstances.
Your API endpoint is taking a long time to send the response and the Axios library is timing out before the response arrives.
You could significantly increase the timeout value for your axios call to test if #2 is what is happening.

Categories