Это сообщение об ошибке отображается при возникновении ошибки в запросе, которая привела к сбою. Он проявится при использовании:
mysql_fetch_array
/ mysqli_fetch_array()
mysql_fetch_assoc()
/ mysqli_fetch_assoc()
mysql_num_rows()
/ mysqli_num_rows()
Примечание. Эта ошибка вызывает не , если на ваш запрос не влияет строка. Только запрос с недопустимым синтаксисом генерирует эту ошибку.
Шаги устранения неполадок
error_reporting(-1);
. Если у вас есть какие-либо синтаксические ошибки, это укажет вам. mysql_error()
. mysql_error()
сообщит о любых ошибках MySQL, возникающих при выполнении вашего запроса. Пример использования: mysql_connect($host, $username, $password) or die("cannot connect");
mysql_select_db($db_name) or die("cannot select DB");
$sql = "SELECT * FROM table_name";
$result = mysql_query($sql);
if (false === $result) {
echo mysql_error();
}
mysql_real_escape_string()
, чтобы избежать ввода. mysqli_*
и mysql_*
. Они не то же самое и не могут использоваться вместе. Другие советы
mysql_*
функции не должны для нового кода. Они больше не поддерживаются, и сообщество приступило к процессу осушки . Вместо этого вы должны узнать о подготовленных операторах и использовать либо PDO , либо MySQLi . Если вы не можете решить, эта статья поможет выбрать. Если вы хотите узнать, вот хороший учебник PDO .
Решение, которое в итоге было реализовано, состояло в том, чтобы использовать оболочку для функции обратного вызова вызова Ajax и в этой проверке обертки для существования определенного элемента в возвращаемом фрагменте HTML. Если элемент был найден, оболочка выполнила перенаправление. В противном случае обертка переадресовала вызов фактической функции обратного вызова.
Например, наша оберточная функция была чем-то вроде:
function cbWrapper(data, funct){
if($("#myForm", data).length > 0)
top.location.href="login.htm";//redirection
else
funct(data);
}
Затем при создании Ajax-вызова мы использовали что-то вроде:
$.post("myAjaxHandler",
{
param1: foo,
param2: bar
},
function(data){
cbWrapper(data, myActualCB);
},
"html"
);
работал для нас, потому что все вызовы Ajax всегда возвращают HTML внутри элемента DIV, который мы используем для замены части страницы. Кроме того, нам нужно было перенаправить на страницу входа.
Я решил эту проблему:
public ActionResult Index(){
if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.Response.AddHeader("REQUIRES_AUTH","1");
}
return View();
}
ajaxSuccess
и проверить, существует ли заголовок: $(document).ajaxSuccess(function(event, request, settings) {
if (request.getResponseHeader('REQUIRES_AUTH') === '1') {
window.location = '/';
}
});
Наконец, я решу проблему, добавив пользовательский HTTP Header
. Как раз перед ответом для каждого запроса на стороне сервера, я добавляю текущий запрошенный url в заголовок ответа.
Мой тип приложения на сервере Asp.Net MVC
, и у него есть хорошее место для этого. в Global.asax
я реализовал событие Application_EndRequest
так:
public class MvcApplication : System.Web.HttpApplication
{
// ...
// ...
protected void Application_EndRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
app.Context.Response.Headers.Add("CurrentUrl",app.Context. Request.CurrentExecutionFilePath);
}
}
Он отлично работает для меня! Теперь в каждом ответе JQuery
$.post
у меня есть запрошенные url
, а также другие заголовки ответов, которые появляются в результате POST
метода по статусу 302
, 303
, ....
, и многое другое важно, так как нет необходимости изменять код на стороне сервера или на стороне клиента.
, а следующая - возможность получить доступ к другой информации о post action таких ошибках, сообщения и ..., таким образом.
Я разместил это, возможно, помог кому-то:)
У меня была эта проблема в приложении django, с которым я возился (отказ от ответственности: я возился, чтобы учиться, и я никоим образом не специалист). То, что я хотел сделать, это использовать jQuery ajax для отправки запроса DELETE на ресурс, удалить его на стороне сервера, а затем отправить перенаправление обратно (в основном) на главную страницу. Когда я отправил HttpResponseRedirect('/the-redirect/')
из скрипта python, метод ajax jQuery получал 200 вместо 302. Таким образом, я сделал, чтобы отправить ответ 300 с помощью:
response = HttpResponse(status='300')
response['Location'] = '/the-redirect/'
return response
Затем я отправил / обработал запрос на клиенте с jQuery.ajax, например:
<button onclick="*the-jquery*">Delete</button>
where *the-jquery* =
$.ajax({
type: 'DELETE',
url: '/resource-url/',
complete: function(jqxhr){
window.location = jqxhr.getResponseHeader('Location');
}
});
Возможно, использование 300 не является «правильным», но по крайней мере оно работает так, как я этого хотел.
PS: это была огромная боль для редактирования на мобильной версии SO. Глупый интернет-провайдер подал запрос на отмену моего обслуживания, когда я закончил с моим ответом!
Я просто хотел защелкнуться на любые запросы ajax для всей страницы. @SuperG заставил меня начать. Вот что я закончил с:
// redirect ajax requests that are redirected, not found (404), or forbidden (403.)
$('body').bind('ajaxComplete', function(event,request,settings){
switch(request.status) {
case 301: case 404: case 403:
window.location.replace("http://mysite.tld/login");
break;
}
});
Я хотел специально проверить определенные коды состояния http, чтобы основать мое решение. Однако вы можете просто привязать ajaxError к чему-то другому, кроме успеха (возможно, только 200)? Я мог бы просто написать:
$('body').bind('ajaxError', function(event,request,settings){
window.location.replace("http://mysite.tld/login");
}
Мне нравится метод Тиммерца с небольшим завихрением лимона. Если вы когда-либо возвращаете contentType text / html, когда ожидаете JSON, вы, скорее всего, будете перенаправлены. В моем случае я просто перезагружаю страницу и перенаправляется на страницу входа. О, и проверьте, что состояние jqXHR равно 200, что кажется глупым, потому что вы находитесь в функции ошибки, верно? В противном случае допустимые ошибки приведут к повторной перезагрузке (oops)
$.ajax(
error: function (jqXHR, timeout, message) {
var contentType = jqXHR.getResponseHeader("Content-Type");
if (jqXHR.status === 200 && contentType.toLowerCase().indexOf("text/html") >= 0) {
// assume that our login has expired - reload our current page
window.location.reload();
}
});
Позвольте мне просто повторить проблему, описанную @Steg
. У меня была аналогичная проблема с вашей. Я выполняю запрос ajax, который имеет 2 возможных ответа: один, который перенаправляет браузер на новую страницу и заменяет существующую HTML-форму на текущей странице новым.
blockquote>ИМХО это является реальной проблемой и должен быть официально распространен на существующие HTTP-стандарты.
Я считаю, что новым стандартом Http будет использоваться новый код состояния. значение: в настоящее время
301/302
сообщает браузеру перейти и получить содержимое этого запроса к новомуlocation
.В расширенном стандарте он скажет, что если ответ
status: 308
(просто пример), браузер должен перенаправить главную страницу на предоставленнуюlocation
.Это сказано; Я склонен уже имитировать это поведение future , и поэтому, когда необходим document.redirect, я отвечаю на сервер как:
status: 204 No Content x-status: 308 Document Redirect x-location: /login.html
Когда JS получает "
status: 204
", он проверяет существование заголовкаx-status: 308
и делает document.redirect на странице, представленной в заголовкеlocation
.Это имеет для вас какое-то значение?
Я думаю, что лучший способ справиться с этим - использовать существующие коды ответа HTTP-протокола, в частности 401 Unauthorized
.
Вот как я его решил:
$('body').bind('ajaxSuccess',function(event,request,settings){
if (401 == request.status){
window.location = '/users/login';
}
}).bind('ajaxError',function(event,request,settings){
if (401 == request.status){
window.location = '/users/login';
}
});
IMO это более общий и вы не пишете новые пользовательские спецификации / заголовок. Вам также не нужно изменять какие-либо из ваших существующих вызовов ajax.
Изменить: в комментарии @ Rob ниже, 401 (код состояния HTTP для ошибок аутентификации) должен быть индикатором. См. 403 Запрещенные vs 401 Неавторизованные HTTP-ответы для более подробной информации. При этом некоторые веб-фреймворки используют 403 для ошибок аутентификации и авторизации, поэтому соответствующим образом адаптируйте их. Спасибо, Роб.
Вы также можете подключить прототип отправки XMLHttpRequest. Это будет работать для всех отправлений (jQuery / dojo / etc) с помощью одного обработчика.
Я написал этот код для обработки ошибки на 500 страниц с истекшим сроком действия, но он должен работать так же, как и ловушку перенаправления 200. Готов к записи wikipedia в XMLHttpRequest onreadystatechange о значении readyState.
// Hook XMLHttpRequest
var oldXMLHttpRequestSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function() {
//console.dir( this );
this.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 500 && this.responseText.indexOf("Expired") != -1) {
try {
document.documentElement.innerHTML = this.responseText;
} catch(error) {
// IE makes document.documentElement read only
document.body.innerHTML = this.responseText;
}
}
};
oldXMLHttpRequestSend.apply(this, arguments);
}
У меня есть рабочий solulion, используя ответы от @John и @Arpad link и @RobWinch link
Я использую Spring Security 3.2.9 и jQuery 1.10.2.
Расширить класс Spring, чтобы вызвать ответ 4XX только из запросов AJAX:
public class CustomLoginUrlAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public CustomLoginUrlAuthenticationEntryPoint(final String loginFormUrl) {
super(loginFormUrl);
}
// For AJAX requests for user that isn't logged in, need to return 403 status.
// For normal requests, Spring does a (302) redirect to login.jsp which the browser handles normally.
@Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException)
throws IOException, ServletException {
if ("XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
} else {
super.commence(request, response, authException);
}
}
}
applicationContext-security.xml
<security:http auto-config="false" use-expressions="true" entry-point-ref="customAuthEntryPoint" >
<security:form-login login-page='/login.jsp' default-target-url='/index.jsp'
authentication-failure-url="/login.jsp?error=true"
/>
<security:access-denied-handler error-page="/errorPage.jsp"/>
<security:logout logout-success-url="/login.jsp?logout" />
...
<bean id="customAuthEntryPoint" class="com.myapp.utils.CustomLoginUrlAuthenticationEntryPoint" scope="singleton">
<constructor-arg value="/login.jsp" />
</bean>
...
<bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache">
<property name="requestMatcher">
<bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher">
<constructor-arg>
<bean class="org.springframework.security.web.util.matcher.MediaTypeRequestMatcher">
<constructor-arg>
<bean class="org.springframework.web.accept.HeaderContentNegotiationStrategy"/>
</constructor-arg>
<constructor-arg value="#{T(org.springframework.http.MediaType).APPLICATION_JSON}"/>
<property name="useEquals" value="true"/>
</bean>
</constructor-arg>
</bean>
</property>
</bean>
В моих JSP добавьте глобальный обработчик ошибок AJAX, как показано здесь здесь
$( document ).ajaxError(function( event, jqxhr, settings, thrownError ) {
if ( jqxhr.status === 403 ) {
window.location = "login.jsp";
} else {
if(thrownError != null) {
alert(thrownError);
} else {
alert("error");
}
}
});
. Также удалите существующие обработчики ошибок из вызовов AJAX в JSP-страницах:
var str = $("#viewForm").serialize();
$.ajax({
url: "get_mongoDB_doc_versions.do",
type: "post",
data: str,
cache: false,
async: false,
dataType: "json",
success: function(data) { ... },
// error: function (jqXHR, textStatus, errorStr) {
// if(textStatus != null)
// alert(textStatus);
// else if(errorStr != null)
// alert(errorStr);
// else
// alert("error");
// }
});
Надеюсь, что это поможет другим.
Update1 Я обнаружил, что мне нужно добавить параметр (always-use-default-target = "true") в конфигурацию формы входа. Это было необходимо, так как после запроса AJAX перенаправляется на страницу входа (из-за истекшего сеанса), Spring запоминает предыдущий запрос AJAX и автоматически перенаправляет его после входа в систему. Это приведет к отображению возвращаемого JSON на странице браузера. Конечно, не то, что я хочу.
Update2 Вместо использования always-use-default-target="true"
используйте пример @RobWinch блокировки запросов AJAX из requstCache. Это позволяет нормальным ссылкам перенаправляться на исходную цель после входа в систему, но AJAX переходит на домашнюю страницу после входа в систему.
Никакие браузеры не обрабатывают 301 и 302 ответов правильно. И на самом деле стандарт даже говорит, что они должны обрабатывать их «прозрачно», что является МАССИВНОЙ головной болью для поставщиков библиотеки Ajax. В Ra-Ajax мы были вынуждены использовать HTTP-код ответа HTTP 278 (только некоторый «неиспользуемый» код успеха) для обработки прозрачных переадресаций с сервера ...
Это действительно раздражает я, и если у кого-то здесь есть «pull» в W3C, я был бы признателен, что вы могли бы сообщить W3C знать , что нам действительно нужно обрабатывать 301 и 302 коды ...! ;)
Объединив то, что сказал Владимир Прудников и Томас Хансен:
blockquote>if request.is_ajax(): response.status_code = 278
Это делает браузер успешным ответом на ответ.
- В своем JS убедитесь, что представление формы через Ajax, проверьте код ответа и при необходимости перенаправите:
blockquote>$('#my-form').submit(function(event){ event.preventDefault(); var options = { url: $(this).attr('action'), type: 'POST', complete: function(response, textStatus) { if (response.status == 278) { window.location = response.getResponseHeader('Location') } else { ... your code here ... } }, data: $(this).serialize(), }; $.ajax(options); });
У меня не было никакого успеха в решении заголовка - они никогда не были получены в моем методе ajaxSuccess / ajaxComplete. Я использовал ответ Штега с пользовательским ответом, но я немного изменил сторону JS. Я настраиваю метод, который я вызываю в каждой функции, поэтому я могу использовать стандартные методы $.get
и $.post
.
function handleAjaxResponse(data, callback) {
//Try to convert and parse object
try {
if (jQuery.type(data) === "string") {
data = jQuery.parseJSON(data);
}
if (data.error) {
if (data.error == 'login') {
window.location.reload();
return;
}
else if (data.error.length > 0) {
alert(data.error);
return;
}
}
}
catch(ex) { }
if (callback) {
callback(data);
}
}
Пример использования в нем ...
function submitAjaxForm(form, url, action) {
//Lock form
form.find('.ajax-submit').hide();
form.find('.loader').show();
$.post(url, form.serialize(), function (d) {
//Unlock form
form.find('.ajax-submit').show();
form.find('.loader').hide();
handleAjaxResponse(d, function (data) {
// ... more code for if auth passes ...
});
});
return false;
}
Я просто хотел поделиться своим подходом, так как это могло бы помочь кому-то:
В основном я включил модуль JavaScript, который обрабатывает элементы аутентификации, такие как отображение имени пользователя, а также этот случай, обрабатывающий перенаправление на логин page.
Мой сценарий: у нас в основном есть ISA-сервер, между которым прослушиваются все запросы и отвечает 302 и заголовок местоположения на нашу страницу входа.
В моем модуле JavaScript мой первоначальный подход был чем-то вроде
$(document).ajaxComplete(function(e, xhr, settings){
if(xhr.status === 302){
//check for location header and redirect...
}
});
. Проблема (как уже упоминалось выше) заключается в том, что браузер обрабатывает перенаправление самостоятельно, поэтому мой обратный вызов ajaxComplete
никогда не вызывался, но вместо этого я получил ответ из уже перенаправленной страницы входа, которая, очевидно, была status 200
. Проблема: как вы обнаруживаете, является ли успешный ответ 200 вашей фактической страницей входа или просто какой-либо другой произвольной страницей?
Поскольку я не смог захватить перенаправление 302 ответов, я добавил заголовок LoginPage
на моей странице входа, в которой был URL-адрес самой страницы входа. В модуле я теперь слушаю заголовок и делаю перенаправление:
if(xhr.status === 200){
var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
window.location.replace(loginPageRedirectHeader);
}
}
... и работает как шарм :). Вы можете задаться вопросом, почему я включаю url в заголовок LoginPage
... ну в основном потому, что я не нашел способа определить URL-адрес GET
в результате автоматического перенаправления местоположения с объекта xhr
...
Если вы также хотите передать значения, вы также можете установить переменные сеанса и получить доступ. Например: в jsp вы можете написать
<% HttpSession ses = request.getSession(true);
String temp=request.getAttribute("what_you_defined"); %>
. Затем вы можете сохранить это значение темпа в своем javascript переменная и игра вокруг
Другое решение, которое я нашел (особенно полезно, если вы хотите установить глобальное поведение), заключается в использовании метода $.ajaxsetup()
вместе с свойством statusCode
. Как и другие указатели, не используйте код статуса перенаправления (3xx
), вместо этого используйте код статуса 4xx
и обрабатываете клиентскую сторону с переадресацией.
$.ajaxSetup({
statusCode : {
400 : function () {
window.location = "/";
}
}
});
Замените 400
кодом состояния вы хотите справиться. Как уже упоминалось 401 Unauthorized
, может быть хорошей идеей. Я использую 400
, поскольку он очень неспецифичен, и я могу использовать 401
для более конкретных случаев (например, неправильные учетные данные). Поэтому вместо перенаправления непосредственно ваш backend должен возвращать код ошибки 4xx
, когда время ожидания сеанса и вы обрабатываете клиентскую часть перенаправления. Работает идеально для меня даже с фреймворками, такими как backbone.js
Хотя ответы, похоже, работают для людей, если вы используете Spring Security, я нашел расширение LoginUrlAuthenticationEntryPoint и добавление определенного кода для более эффективного управления AJAX. Большинство примеров перехватывают все перенаправляют не только неудачи аутентификации. Это было нежелательно для проекта, над которым я работаю. Возможно, вам также потребуется расширить ExceptionTranslationFilter и переопределить метод sendStartAuthentication, чтобы удалить шаг кэширования, если вы не хотите, чтобы сбойный запрос AJAX был кеширован.
Пример AjaxAwareAuthenticationEntryPoint:
public class AjaxAwareAuthenticationEntryPoint extends
LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginUrl) {
super(loginUrl);
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
if (isAjax(request)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), "Please re-authenticate yourself");
} else {
super.commence(request, response, authException);
}
}
public static boolean isAjax(HttpServletRequest request) {
return request != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
}
Я решил это, поставив следующее на моей странице login.php.
<script type="text/javascript">
if (top.location.href.indexOf('login.php') == -1) {
top.location.href = '/login.php';
}
</script>
Попробуйте
$(document).ready(function () {
if ($("#site").length > 0) {
window.location = "<%= Url.Content("~") %>" + "Login/LogOn";
}
});
Поместите его на страницу входа. Если он был загружен в div на главной странице, он будет перенаправлен до страницы входа. «#site» - это идентификатор div, который находится на всех страницах, кроме страницы входа.
<script>
function showValues() {
var str = $("form").serialize();
$.post('loginUser.html',
str,
function(responseText, responseStatus, responseXML){
if(responseStatus=="success"){
window.location= "adminIndex.html";
}
});
}
</script>
Эта проблема может возникнуть при использовании метода ASP.NET MVC RedirectToAction. Чтобы предотвратить отображение формы в div, вы можете просто сделать какой-то фильтр ответа ajax для входящих ответов с $ .ajaxSetup. Если ответ содержит перенаправление MVC, вы можете оценить это выражение на стороне JS. Пример кода для JS ниже:
$.ajaxSetup({
dataFilter: function (data, type) {
if (data && typeof data == "string") {
if (data.indexOf('window.location') > -1) {
eval(data);
}
}
return data;
}
});
Если данные: "window.location = '/ Acount / Login'" выше фильтр поймает это и оценит, чтобы сделать перенаправление вместо того, чтобы отображать данные.
Большинство данных решений используют обходной путь, используя дополнительный заголовок или неадекватный HTTP-код. Эти решения, скорее всего, будут работать, но немного «взломать». Я придумал другое решение.
Мы используем WIF, который настроен на перенаправление (passiveRedirectEnabled = "true") на ответ 401. Переадресация полезна при обращении с обычными запросами, но не будет работать для AJAX-запросов (поскольку браузеры не будут выполнять 302 / переадресацию).
Используя следующий код в вашем global.asax, вы можете отключить перенаправление для запросов AJAX:
void WSFederationAuthenticationModule_AuthorizationFailed(object sender, AuthorizationFailedEventArgs e)
{
string requestedWithHeader = HttpContext.Current.Request.Headers["X-Requested-With"];
if (!string.IsNullOrEmpty(requestedWithHeader) && requestedWithHeader.Equals("XMLHttpRequest", StringComparison.OrdinalIgnoreCase))
{
e.RedirectToIdentityProvider = false;
}
}
Это позволяет вам возвращать 401 ответа на запросы AJAX, которые могут быть у вашего javascript затем выполните перезагрузку страницы. Перезагрузка страницы вызовет 401, которые будут обрабатываться WIF (и WIF перенаправит пользователя на страницу входа в систему).
Пример javascript для обработки ошибок 401:
$(document).ajaxError(function (event, jqxhr, settings, exception) {
if (jqxhr.status == 401) { //Forbidden, go to login
//Use a reload, WIF will redirect to Login
location.reload(true);
}
});
Я прочитал этот вопрос и внедрил подход, который был сформулирован относительно установки кода статуса ответа на 278, чтобы избежать прозрачности работы браузера с переадресацией. Несмотря на то, что это сработало, я был немного недоволен, так как это немного взломал.
После того, как я снова начал копаться, я бросил этот подход и использовал JSON . В этом случае все ответы на запросы ajax имеют код состояния 200, а тело ответа содержит объект JSON, который построен на сервере. Javascript на клиенте может затем использовать объект JSON, чтобы решить, что ему нужно делать.
У меня была аналогичная проблема с вашей. Я выполняю запрос ajax, который имеет 2 возможных ответа: один, который перенаправляет браузер на новую страницу и заменяет существующую HTML-форму на текущей странице новой. Код jquery для этого выглядит примерно так:
$.ajax({
type: "POST",
url: reqUrl,
data: reqBody,
dataType: "json",
success: function(data, textStatus) {
if (data.redirect) {
// data.redirect contains the string URL to redirect to
window.location.href = data.redirect;
}
else {
// data.form contains the HTML for the replacement form
$("#myform").replaceWith(data.form);
}
}
});
Объект «данные» объекта JSON построен на сервере, чтобы иметь 2 члена: data.redirect и data.form. Я нашел этот подход намного лучше.
Используйте низкоуровневый вызов $.ajax()
:
$.ajax({
url: "/yourservlet",
data: { },
complete: function(xmlHttp) {
// xmlHttp is a XMLHttpRquest object
alert(xmlHttp.status);
}
});
Попробуйте это для перенаправления:
if (xmlHttp.code != 200) {
top.location.href = '/some/other/page';
}
У меня есть простое решение, которое работает для меня, не требуется изменение кода сервера ... просто добавьте tsp мускатного ореха ...
$(document).ready(function ()
{
$(document).ajaxSend(
function(event,request,settings)
{
var intercepted_success = settings.success;
settings.success = function( a, b, c )
{
if( request.responseText.indexOf( "<html>" ) > -1 )
window.location = window.location;
else
intercepted_success( a, b, c );
};
});
});
Я проверяю наличие тега html, но вы может изменить indexOf для поиска любой уникальной строки на вашей странице входа ...
Некоторые могут найти ниже полезное:
Я хотел, чтобы клиенты были перенаправлены на страницу входа в систему для любого действия rest, которое отправляется без токена авторизации. Поскольку все мои действия по отдыху основаны на Ajax, мне нужен хороший общий способ перенаправления на страницу входа в систему вместо обработки функции успеха Ajax.
Это то, что я сделал:
В любом запросе Ajax мой сервер вернет ответ Json 200 «НЕОБХОДИМОСТЬ АВТОРИЗАЦИИ» (если клиент должен пройти аутентификацию).
Простой пример в Java (на стороне сервера):
@Secured
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
private final Logger m_logger = LoggerFactory.getLogger(AuthenticationFilter.class);
public static final String COOKIE_NAME = "token_cookie";
@Override
public void filter(ContainerRequestContext context) throws IOException {
// Check if it has a cookie.
try {
Map<String, Cookie> cookies = context.getCookies();
if (!cookies.containsKey(COOKIE_NAME)) {
m_logger.debug("No cookie set - redirect to login page");
throw new AuthenticationException();
}
}
catch (AuthenticationException e) {
context.abortWith(Response.ok("\"NEED TO AUTHENTICATE\"").type("json/application").build());
}
}
}
В моем Javascript я добавил следующий код:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
var originalSuccess = options.success;
options.success = function(data) {
if (data == "NEED TO AUTHENTICATE") {
window.location.replace("/login.html");
}
else {
originalSuccess(data);
}
};
});
И это все.
в сервлете вы должны поместить response.setStatus(response.SC_MOVED_PERMANENTLY);
, чтобы отправить статус xmlHttp '301', необходимый для перенаправления ...
, а в функции $ .ajax вы не должны использовать .toString()
function ..., just
if (xmlHttp.status == 301) {
top.location.href = 'xxxx.jsp';
}
проблема в том, что она не очень гибкая, вы не можете решить, куда вы хотите перенаправить ..
перенаправление через сервлеты должно быть лучшим способом. но я все еще не могу найти правильный способ сделать это.
Кроме того, вы, вероятно, захотите перенаправить пользователя к указанному в URL-адресе заголовков. Итак, это будет выглядеть так:
$.ajax({
//.... other definition
complete:function(xmlHttp){
if(xmlHttp.status.toString()[0]=='3'){
top.location.href = xmlHttp.getResponseHeader('Location');
}
});
UPD: Opps. Иметь ту же задачу, но она не работает. Делать это. Я покажу вам решение, когда найду его.
Я знаю, что эта тема старая, но я дам еще один подход, который я нашел и ранее описал здесь здесь . В основном я использую ASP.MVC с WIF (но это не очень важно для контекста этой темы - ответ адекватен независимо от того, какие рамки используются. Указание остается неизменным - решение проблем, связанных с ошибками аутентификации, в то время как выполнение запросов ajax) .
Подход, показанный ниже, может быть применен ко всем запросам ajax из коробки (если они явно не переопределяют событие beforeSend).
$.ajaxSetup({
beforeSend: checkPulse,
error: function (XMLHttpRequest, textStatus, errorThrown) {
document.open();
document.write(XMLHttpRequest.responseText);
document.close();
}
});
Перед выполнением любого запроса ajax CheckPulse
(метод контроллера, который может быть чем-то простейшим):
[Authorize]
public virtual void CheckPulse() {}
Если пользователь не аутентифицирован (токен истек), такой метод не может быть доступен (защищен атрибутом Authorize
). Поскольку структура обрабатывает аутентификацию, а токен истекает, он передает HTTP-статус 302 в ответ. Если вы не хотите, чтобы ваш браузер обрабатывал 302 ответ прозрачно, поймайте его в Global.asax и измените статус ответа - например, до 200 OK. Кроме того, добавьте заголовок, в котором вам будет предложено обработать такой ответ особым образом (позже на стороне клиента):
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302
&& (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
{
Context.Response.StatusCode = 200;
Context.Response.AddHeader("REQUIRES_AUTH", "1");
}
}
Наконец, на стороне клиента проверьте такой пользовательский заголовок. Если присутствует - необходимо выполнить полное перенаправление на страницу входа в систему (в моем случае window.location
заменяется URL-адресом из запроса, который автоматически обрабатывается моей каркасом).
function checkPulse(XMLHttpRequest) {
var location = window.location.href;
$.ajax({
url: "/Controller/CheckPulse",
type: 'GET',
async: false,
beforeSend: null,
success:
function (result, textStatus, xhr) {
if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
XMLHttpRequest.abort(); // terminate further ajax execution
window.location = location;
}
}
});
}
Я решил эту проблему следующим образом:
Добавить промежуточное программное обеспечение для обработки ответа, если оно является перенаправлением для запроса ajax, изменить ответ на нормальный ответ с URL-адресом перенаправления.
class AjaxRedirect(object):
def process_response(self, request, response):
if request.is_ajax():
if type(response) == HttpResponseRedirect:
r = HttpResponse(json.dumps({'redirect': response['Location']}))
return r
return response
Затем в ajaxComplete, если ответ содержит перенаправление, он должен быть перенаправлен, поэтому измените местоположение браузера.
$('body').ajaxComplete(function (e, xhr, settings) {
if (xhr.status == 200) {
var redirect = null;
try {
redirect = $.parseJSON(xhr.responseText).redirect;
if (redirect) {
window.location.href = redirect.replace(/\?.*$/, "?next=" + window.location.pathname);
}
} catch (e) {
return;
}
}
}