Тип содержимого ответа отличается от ожидаемого
У меня есть виджет календаря jquery, который запрашивает несколько источников событий на сервере, и все эти источники возвращают одинаковые ответы в формате JSON.
Что действительно раздражает, так это то, что когда срок действия файла cookie пользователя истекает, все эти источники перенаправляют пользователя на страницу входа, возвращающую содержимое HTML.
Я посмотрел на запрос с помощью fiddler и вижу два выполненных запроса: первый - это запрос от объекта календаря jquery для обновления событий с http-статусом 302 и сразу после запроса на страницу входа с http-статусом 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
Мой сайт основан на AJAX-вызовах, и этот календарь является лишь примером, объясняющим проблему, с которой я сталкиваюсь. Я хотел бы избежать обработки ошибки при каждом вызове ajax и сделать перенаправление. Оптимальным способом было бы найти способ автоматического отключения пользователя, когда истекает срок его сеансового cookie. Я видел, как это реализовано в некоторой системе электронной почты, которая автоматически создает диалог, сообщающий, что сеанс истек.
Любая помощь в этом направлении?
2 ответа
Когда jQuery выполняет AJAX-запрос, он отправляет HTTP_X_REQUESTED_WITH
заголовок.
Рассматривали ли вы проверку этого заголовка на стороне сервера? Если время сеанса истекло, вместо перенаправления на страницу входа можно вернуть структуру JSON, содержащую сообщение об ошибке "Пожалуйста, войдите в систему".
Это был бы самый чистый метод в моих глазах.
Другой идеей было бы сделать дополнительный Ajax-запрос перед выполнением "настоящего". Если первый запрос не удается или получает text/html
Тип контента обратно, вы знаете, что вы больше не вошли в систему. Не очень элегантно, но проще, чем пытаться подсчитать продолжительность сеанса на стороне клиента (что неизбежно будет ненадежным).
Я полагаю, что вы имеете дело с сеансом, информация о тайм-ауте которого хранится на стороне сервера (клиент не обязательно знает, когда его сеанс больше не будет действительным). Получите эту информацию и отправьте ее клиенту вместе с запросом. Простой setTimeout(notifySessionExpiration, sessTimeout * 1000)
сделает свое дело.
Чтобы ответить на второстепенные вопросы:
$ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) &&
($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')
Будет устанавливать $ajax
Значение true, если вы имеете дело с запросом XML, предполагая, что браузер отправляет совместимые заголовки (что он обычно делает в наши дни).
Вы, вероятно, захотите изолировать часть своего кода, которая отправляет 302 (возможно, контроллер всего приложения, который обрабатывает выборку личной информации пользователя на основе сеанса) и собрать исключение, если $ajax
правда. Вы, вероятно, захотите отправить обратно 401 или 403, а затем сделать так, чтобы ваш обратный вызов Javascript отвечал на этот статус определенным образом (например, перенаправляя на страницу входа или предоставляя всплывающее наложение входа Ajax).
Если это просто игрушечный сайт, и вы хотите испачкать руки, чтобы создать более надежное решение, я могу дать следующие рекомендации.
- Не используйте семантически вводящий в заблуждение детектор XHR: по моему мнению, доставка разного контента разным запрашивающим вполне разумна, если это однотипный контент с определенными адаптациями для запрашивающего (например, причуды браузера). Но когда конкретный запросчик выполняет принципиально другую функциональную роль (например, когда XHR отправляется в ожидании ответа JSON/XML по сравнению с тем, когда браузер отправляет обычный HTTP-запрос для HTML), тогда запрос не должен быть для тот же актив. На мой взгляд, лучшая практика - создавать HTML для
.html
или пути без расширения, напримерGET /mypage.html
или жеGET /mypage
в то время как XHR-ориентированное содержимое должно бытьGET /mypage.json
или жеGET /mypage.xml
природа. Это не значит, что XHR никогда не должен получать HTML-ответ. Иногда это совершенно уместно, например, когда вы загружаете фрагмент HTML для формы входа в систему или просто используете AJAX для переходов страниц. - Внедрите систему, чтобы поддерживать ваш сеанс в действии: если вы хотите, чтобы ваш сеанс истекал только по времени, а не только до тех пор, пока браузер не будет закрыт, а затем выполните вызов на стороне клиента, чтобы обновить сеанс простым AJAX-запросом до его истечения (если страница закрыта, запрос не запускается, что позволяет сеансу истечь по истечении выделенного времени).