Response content type different from what expected
I have a jquery calendar widget that do query several event sources on the server and these sources all returns the same JSON format responses.
What is really annoying is that when the user cookie expires these sources all redirect the user to the login page returning HTML content.
I have looked at the request with fiddler and I can see two request done: first one is a request from the jquery calendar object to update the events with http status 302 and immediately after a request to the login page with http status 200.
GET /xyz/Adempimenti/GetEvents?_=1289170335910&start=1288566000&end=1291590000 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/javascript, */*; q=0.01
HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Location: /xyz/Login/LogOn?ReturnUrl=%2fxyz%2fAdempimenti%2fGetEvents%3f_%3d1289170335910%26start%3d1288566000%26end%3d1291590000&_=1289170335910&start=1288566000&end=1291590000
My site is deeply based on ajax calls and this one of the calendar is just an example to explain the problem i am facing to. I would like to avoid to handle the error on every ajax call and do a redirect. The optimal way would be to find a way to automatically disconnect the user when his session cookie expires. I have seen t开发者_如何学运维his implemented in some web email system that automatically create a dialog saying that the session has expired.
Any help on this direction?
When jQuery does an AJAX request, it sends the HTTP_X_REQUESTED_WITH
header.
Have you considered checking for that header on server side? If the session has timed out, instead of redirecting to the login page, you could return a JSON structure containing the "please log in" error message.
That would be the cleanest method in my eyes.
Another idea would be to make an additional Ajax request before doing the "real" one. If the first request fails or gets a text/html
content type back, you know you are no longer logged in. Not very elegant but easier than trying to count the session duration on client side (which is bound to be unreliable).
I believe you're dealing with a session, whose timeout information is stored server-side (the client doesn't necessarily know when his session will no longer be valid). Get that information and send it to the client with the request. The a simple setTimeout(notifySessionExpiration, sessTimeout * 1000)
will do the trick.
To answer peripheral questions:
$ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')
Will set $ajax
to true if you're dealing with an XML request, assuming the browser sends compliant headers (which it tends to do these days).
You will probably want to isolate the part of your code that sends the 302 (perhaps an application-wide controller that handles fetching the user's personal information based on the session) and put together an exception if $ajax
is true. You'd probably want to send back a 401 or 403 and then have your Javascript callback respond to that status in a particular way (e.g., redirecting to login page or providing an popup Ajax login overlay).
If this is just a toy site and you're willing to get your hands dirty to create a more robust solution, I can make the following recommendations.
- Don't use a semantically misleading XHR detector: in my opinion, delivering different content to different requesters is perfectly reasonable if it's the same-ish content with specific adaptations for the requester (e.g., browser quirks). But when a particular requester has a fundamentally different functional role (e.g., when an XHR gets sent in expecting a JSON/XML response vs. when a browser sends in a normal HTTP request for HTML), then the request shouldn't be for the same asset. The best practice, in my opinion, is to produce HTML for
.html
or extension-less paths, for instanceGET /mypage.html
orGET /mypage
, whereas XHR-tailored content should be of theGET /mypage.json
orGET /mypage.xml
nature. This is not to say that XHR should never get an HTML response. Sometimes, it's perfectly appropriate, like when you're loading an HTML snippet for a login form or if you're just using AJAX for page transitions. - Implement a system to keep your session alive: if you must have your session expire by time alone rather than just lasting until the browser is closed, then put in a client-side call to refresh the session with a simple AJAX request before it expires (if the page is closed, the request isn't fired, allowing the session to expire when the allotted time passes).
精彩评论