Handle 302 status code upon HTML/JS request to server? - javascript

I'm using Require JS and Orace JET
How can we handle the 302 status code or any other status code returned by Server when the session is timeout.
Can it be configured to catch it and redirect the user to a login page upon such cases?

The status code 302 cannot be seen by RequireJS. That's just how browsers work: the browser will see 302 and automatically perform the next HTTP request. RequireJS won't know that there was a redirection.
Any HTTP status code that is an error (500, 400, etc.) will result in a module load failure and onError will be called.

Here is my solution (that works because of luck). Take it just as an inspiration. When session in my app expires, the request is being forwarded using 302 to login page as you would expect. There are 2 main types of requests where it can happen:
REST API call (via XMLHttpRequest)
navigation on page that user did
For #2, the 302 poses no problem. User is simply redirected to login page.
For #1, I can somehow detect it (with some probability) because login page is on different domain that does not support CORS. The XMLHttpRequest request will simply fail with readyState equal to 0 and statusText equal to "error" (because browser will block the XMLHttpRequest to different domain). I have a "listener" (interceptor) on all my REST API calls and whenever some fails with the 0 readyState and "error" statusText, it means that session probably expired.
This is not a solution of course and cannot be used everywhere. Just an idea to think about :)

Related

Differentiate between failed(no network) and cancelled request in ajax error(HTTP status code 0)

I am using Jquery ajaxError to catch all ajax errors. I am having problem with http status code 0. This code is returned when the request fails(no network), or if user refreshes page(or clicks on other tab). I want to differentiate between both. Is there any way to do so?
I think there is not a straightforward solution but there is a workaround.
On http status code 0 you can check...
if(navigator.onLine)
which will return whether there is some network connected or not.

Browser mangling 302 responses from Ajax requests

I have the following.
AJAX request made to server from mydomain.blah.com
Server returns 302 but to a slight different domain blah.com not mydomain.blah.com
Browser appears to mangle response. Instead of the 302 coming into my error callback a response with no response body and no status code is returned.
Further details
Looking at request in IE 10 it is marked as aborted.
In FF , firebug shows the 302 coming back but it never been handled.
To complicate matters (although I don't this is relevant) there are multiple ajax requests sent over.
The reason why the 302 is returned is because my server session is timed out and I am being redirected to a login page. I don't have much control over the server.
I want to get the response code 302 sent from my server into my error callback. This is what I want to achieve.
The ajax calls are being made using JQuery.
Any help appreciated.
If it is offical policy for browsers to "mangle" 302 responses to difference domains from ajax calls then if anyone could provide a reference that would be cool. Then I'd know there is not much I can do about this.

Capture HTTP Status 300 for redirect download links

I'm developing a Chrome Extension to download links on a webpage.
I came across some links there were not a direct download, for example like this one http://downloads.sourceforge.net/sevenzip/7z920-x64.msi
When I trace the link on fiddler, I'm getting HTTP Status 302 (which is a redirect). So I'm trying to test the link before downloading using XMLHTTPRequest, but I can't retrieve status 302, XMLHTTPRequest is only retrieving the file status which is 200?
Is there a trick around this to make it stop at 302 or perhaps a different alternative to AJAX calls?
This is possible with the use of the chrome.webRequest api. 302's and the like are normally handled silently by the browser, but you can use this method to stop them or make them more visible to your code.
chrome.webRequest.onHeadersReceived.addListener(function(details){
var redirUrl;
details.responseHeaders.forEach(function(v,i,a){
if(v.name == "Location"){
redirUrl = v.value;
details.responseHeaders.splice(i,1); //Kill the redirect
}
});
if(redirUrl)
details.responseHeaders.push({name:"redirUrl",value:redirUrl});
return {responseHeaders:details.responseHeaders};
},
{urls: ["http://*/*"],tabId:-1},["responseHeaders","blocking"]);
I specified a tabId of -1, which means it should only work for requests not coming from a tab, i.e. a background page. This will silently prevent the redirect while allowing you access to both the 302 status and the url to redirect to.

How to tell if an XMLHTTPRequest hit the browser cache

If it possible to tell (within javascript execution) if a GET XMLHTTPRequest hit the browser cache instead of getting its response from the server?
From the XMLHttpRequest spec:
For 304 Not Modified responses that are a result of a user agent
generated conditional request the user agent must act as if the server
gave a 200 OK response with the appropriate content.
In other words, the browser will always give status code 200 OK, even for requests that hit the browser cache.
However, the spec also says:
The user agent must allow author request headers to override automatic cache
validation (e.g. If-None-Match or If-Modified-Since), in which case
304 Not Modified responses must be passed through.
So, there is a workaround to make the 304 Not Modified responses visible to your JavaScript code.
When making an ajax request, You get the response code
if (request.readyState == 4) {
if (request.status == 200) { // this number.
...
status 200 means you are getting a fresh copy of the data:
The request has succeeded. The information returned with the response is dependent on the method used in the request -
status 304 means the data has not changed and you will get it from the browser cache:
If the client has performed a conditional GET request and access is allowed, but the document has not been modified, the server SHOULD respond with this status code.
Read more on Status Code
Update:
You can add a cache buster to your URL to guarantee that you always hit the server:
var ajaxUrl = "/path?cache="+(Math.random()*1000000);
From http://www.w3.org/TR/2012/WD-XMLHttpRequest-20121206/
For 304 Not Modified responses that are a result of a user agent
generated conditional request the user agent must act as if the server
gave a 200 OK response with the appropriate content. The user agent
must allow author request headers to override automatic cache
validation (e.g. If-None-Match or If-Modified-Since), in which case
304 Not Modified responses must be passed through. [HTTP]
I find this rather vague. My assumption would be if a resource is conditionally requested, you would see the 304 response code. But, as I explained in another comment (source: https://developers.google.com/speed/docs/best-practices/caching), there might not even be a request if the last response server http header for that resource had set Cache-Control: max-age or Expires set sometime in the future. In this case, I'm not sure what ought to happen.
This answer is based on the assumption that you mean browser only cache, with no 304's taking place (modified-since, etag etc).
Check how long the request took - if it was resolved from cache then it should take close to 0ms.
Do you use Firefox's Firebug?
Firebug has a "Net" panel with an "XHR" filtered view. You should be able to inspect the cache info via the request phase bar, checking the status and/or clicking the triangle to inspect "Headers".
Cached or not cached
Not all network requests are equal - some of them are loaded from the
browser cache instead of the network. Firebug provides status codes
for every request so you can quickly scan and see how effectively your
site is using the cache to optimize page load times.
Firebug Net Panel docs are here.
Chrome/Safari/Opera all have similar debugging tools. Just found a good list here (most should have tools to inspect XHR).
EDIT:
In order to somewhat redeem myself...
As ibu has answered, I'd also start by checking the status code of the response.
If you're using jQuery:
statusCode(added 1.5)
Map Default: {}
A map of numeric HTTP codes and functions to be called when the
response has the corresponding code. For example, the following will
alert when the response status is a 404:
$.ajax({
statusCode: {
404: function() {
alert("page not found");
}
}
});
If the request is successful, the status code functions take the same
parameters as the success callback; if it results in an error, they
take the same parameters as the error callback.
jQuery sure does make life easy. :)
To check from a browser such as Google Chrome, hit F12 to open DevTools, navigate to Network, refresh to grab some data, filter by XHR, then click on the correct XHR request. Click on the "headers" sub-tab, then look at Response Headers -> cache-control.
If it says things like no-cache and max-age=0, then you are not caching.
If it says private, then your browser is caching, but the server is not.
If it says public, then you are caching both server side and client side.
More info at Mozilla.org

How to prevent ajax requests to follow redirects using jQuery

I use the jQuery ajax functions to access a web service, but the server, instead of returning a response with a status code describing a problem, the request is redirected to a page with a 200 header, describing the problem. I can't make any changes to this, so I need to solve it on the client somehow.
Example:
A request goes to some URL which is not found, so I receive a 302 Redirect to another location. A new request is sent, and I receive a 200 OK, thus preventing the error callback to fire.
Is there some way I can prevent the ajax request to follow redirects and instead invoke a callback, preferably the error method. Alternatively, is it possible to detect if a redirect has happened in the client?
I find your question interesting, but the problem in whole seems me more a misunderstanding. At least I'll try to explain my understanding of the problem.
The silent (transparent) redirection is the part of XMLHttpRequest specification (see here especially the words "... transparently follow the redirect ..."). The standard mention only that the user agent (the web browser) can prevent or notify of certain kinds of automatic redirections, but it's not a part of XMLHttpRequest. It's the part of HTTP client configuration (OS configuration) or the web browser configuration. So jQuery.ajax can't have any option where you can prevent redirection.
You can see that HTTP redirection is the part of HTTP protocol and not a part of XMLHttpRequest. So it's on the another level of abstraction or the network stack. For example the data from the XMLHttpRequest can be retrieved from the HTTP proxy or from the local browser cache, and it's the part of HTTP protocol. Mostly the server which provide the data and not the client can influence on caching.
You can compare the requirement from your question with the requirement to prevent changing of IP address of the web server or the changing of the IP route during the communication. All the things can be interesting in some scenarios, but there are parts of another level of the communication stack and can't be managed by jQuery.ajax or XMLHttpRequest.
The XMLHttpRequest standard say that the client configuration can have options which prevent redirection. In case of "Microsoft world", which I better know, you can look at WinHttpSetOption function which can be used to set WINHTTP_OPTION_DISABLE_FEATURE option with the WINHTTP_DISABLE_REDIRECTS value. Another way are the usage of WINHTTP_OPTION_REDIRECT_POLICY option with the WINHTTP_OPTION_REDIRECT_POLICY_NEVER value. One more feature which one can use in Windows is the WinHttpSetStatusCallback function which can set callback function received some notifications like WINHTTP_CALLBACK_FLAG_REDIRECT.
So it's do possible to implement your requirements in general, but the solution will be probably not independent from the operation system or the web browser and be not on the level of jQuery.ajax or XMLHttpRequest.
I don't believe it is possible. The underlying library (XHR) makes the new request transparently. That being said, what I have done in these situations (usually a session-timeout type of deal that takes me to a login page) is send back a custom response header. I also have setup a global ajax handler that checks for the presence of that header, and responds appropriately when present (for example, redirecting the whole page to the login screen).
In case you're interested, here's the jQuery code I have to watch for that custom header:
/* redirects main window when AJAX request indicates that the session has expired on the backend. */
function checkSession(event, xhr, ajaxOptions)
{
if (xhr.readyState == 4)
{
if(xhr.getResponseHeader("Login-Screen") != null && xhr.getResponseHeader("Login-Screen").length)
{
window.location.href='sessionExpired.html'; //whatever
}
}
}
$(document).ajaxComplete(checkSession)
I found a feature to check if your call has been redirected. It's xhr.state(): if it's "rejected" then a redirection happened.
Example with success callback:
request.success(function(data, textStatus, xhr)
{
if(xhr.state() == "resolved")
{
//no redirection
}
if(xhr.state() == "rejected")
{
//redirection
}
});
Example with error callback:
request.error(function(xhr, textStatus)
{
if (xhr.state() == "rejected")
{
//redirection
location.href = "loginpage";
} else
{
//some other error happened
alert("error");
}
});
I can't possibly add to the insightful wisdom of the previous coders who've responded, but I will add a specific case that others may find useful to know about.
I came across this 302 silent redirect in the context of SharePoint. I have some simple Javascript client code that pings a SharePoint sub-site, and if it receives a 200 HTTP response, it relocates to that site, via window.location. If it receives anything else, it gives the user a notice that the site doesn't exist.
However, in the case where the site exists but the user does not have permission, SharePoint silently redirects to an AccessDenied.aspx page. SharePoint has already done the HTTP 401 authentication handshake at the server/farm level - the user has access to SharePoint. But the access to the sub-site is handled I suppose using database flags of some sort. The silent redirect bypasses my "else" clause, so I can't throw up my own error. In my case, this is not a show-stopper - it is consistent predictable behavior. But it was a little surprising, and I learned something about HTTP requests in the process!
I was interested in the same thing and could not find the state() method mentioned by Takman and did a little digging for myself. For the sake of people turning up here in search of an answer, here are my findings:
As stated multiple times, you cannot prevent redirects, but you can detect them. According to MDN you can use the responseURL of the XMLHttpRequestObject, which will contain the final URL the response came from, after all redirects. Only caveat is that it is not supported by Internet Explorer (Edge has it). Since the xhr/jqXHR passed into the success/done function of jquery is an extension of the actual XMLHttpRequest, it should be available there, too.
While it is not possible to disable location redirect following in XmlHttpRequests, it is when using fetch():
fetch('url', {redirect: manual});
I suppose you receive a 200 response because the second time there is no redirection, because the 404 page does not expire, it is saved in the cache. That is to say that the second time the browser gives you the page in the cache.
There is a property "cache" in the ajax jquery.
http://api.jquery.com/jQuery.ajax/
You should write it to "false"
I'm not sure if this will apply in your case, but you can write code to respond to specific status codes in AJAX function -
$.ajax({
url: '/admin/secret/data',
type: 'POST',
contentType: 'application/json; charset=utf-8',
statusCode: {
200: function (data) {
alert('302: Occurred');
// Bind the JSON data to the UI
},
401: function (data) {
alert('401: Occurred');
// Handle the 401 error here.
}
}
});
In the request headers in the case of ajax request you will have the following
X-Requested-With XMLHttpRequest
By this criteria on the server side you can filter requests.

Categories

Resources