我$.post()
使用Ajax调用servlet,然后使用生成的HTML片段替换div
用户当前页面中的元素。但是,如果会话超时,服务器将发送重定向指令以将用户发送到登录页面。在这种情况下,jQuery用div
登录页面的内容替换了该元素,从而迫使用户的眼睛确实看到了一个罕见的场景。
如何使用jQuery 1.2.6从Ajax调用管理重定向指令?
我$.post()
使用Ajax调用servlet,然后使用生成的HTML片段替换div
用户当前页面中的元素。但是,如果会话超时,服务器将发送重定向指令以将用户发送到登录页面。在这种情况下,jQuery用div
登录页面的内容替换了该元素,从而迫使用户的眼睛确实看到了一个罕见的场景。
如何使用jQuery 1.2.6从Ajax调用管理重定向指令?
If you also want to pass the values then you can also set the session variables and access Eg: In your jsp you can write
<% HttpSession ses = request.getSession(true);
String temp=request.getAttribute("what_you_defined"); %>
And then you can store this temp value in your javascript variable and play around
如果您使用的是Spring Security,答案似乎对某些人有用,但我发现可以扩展LoginUrlAuthenticationEntryPoint并添加特定的代码来更健壮地处理AJAX。大多数示例拦截所有重定向,而不仅仅是身份验证失败。对于我从事的项目来说,这是不可取的。如果您不希望缓存失败的AJAX请求,则可能还需要扩展ExceptionTranslationFilter并重写“ sendStartAuthentication”方法以删除缓存步骤。
示例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"));
}
}
尝试
$(document).ready(function () {
if ($("#site").length > 0) {
window.location = "<%= Url.Content("~") %>" + "Login/LogOn";
}
});
将其放在登录页面上。如果已将其加载到主页的div中,它将重定向到登录页面。“ #site”是位于除登录页面以外的所有页面上的div的ID。
我有一个适用于我的简单解决方案,无需更改服务器代码...只需添加一小撮肉豆蔻...
$(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来搜索登录页面中存在的唯一字符串...
给定的大多数解决方案都使用一种变通方法,即使用额外的标头或不正确的HTTP代码。这些解决方案很可能会起作用,但会有点“棘手”。我想出了另一个解决方案。
我们使用的WIF已配置为在401响应上重定向(passiveRedirectEnabled =“ true”)。重定向在处理普通请求时很有用,但不适用于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;
}
}
这样,您就可以为AJAX请求返回401响应,然后您的JavaScript可以通过重新加载页面来处理该响应。重新加载页面将抛出401,将由WIF处理(WIF会将用户重定向到登录页面)。
处理401错误的示例JavaScript:
$(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);
}
});
我发现的另一种解决方案(如果要设置全局行为特别有用)是将该$.ajaxsetup()
方法与statusCode
property一起使用。就像其他人指出的那样,不要使用重定向状态码(3xx
),而应使用状态码来4xx
处理客户端重定向。
$.ajaxSetup({
statusCode : {
400 : function () {
window.location = "/";
}
}
});
替换400
为您要处理的状态码。像已经提到的那样,401 Unauthorized
可能是一个好主意。我使用,400
因为它是非常不确定的,我可以将其401
用于更具体的情况(例如错误的登录凭据)。因此,4xx
当会话超时并且您要处理客户端重定向时,后端应该返回错误代码,而不是直接重定向。即使使用骨干.js之类的框架,对我来说也很完美
我只想分享我的方法,因为这可能会帮助某人:
我基本上包括一个JavaScript模块,该模块处理身份验证之类的内容,例如显示用户名,在这种情况下,还处理重定向到登录页面的情况。
我的情况是:我们基本上有一个ISA服务器,其间侦听所有请求并以302和登录页面的位置标头作为响应。
在我的JavaScript模块中,我最初的方法是
$(document).ajaxComplete(function(e, xhr, settings){
if(xhr.status === 302){
//check for location header and redirect...
}
});
问题(这里已经提到了很多问题)是浏览器自己处理重定向,因此ajaxComplete
从未调用过我的回调,而是获得了已经重定向的Login页面的响应,显然是a status 200
。问题:您如何检测成功的200响应是您的实际登录页面还是其他任意页面?
由于无法捕获302重定向响应,因此我LoginPage
在登录页面上添加了一个标头,其中包含登录页面本身的网址。现在,在模块中,我监听标题并进行重定向:
if(xhr.status === 200){
var loginPageRedirectHeader = xhr.getResponseHeader("LoginPage");
if(loginPageRedirectHeader && loginPageRedirectHeader !== ""){
window.location.replace(loginPageRedirectHeader);
}
}
...就像魅力:)。您可能想知道为什么我在LoginPage
标头中包含url ...基本上是因为我找不到确定GET
从xhr
对象的自动位置重定向得到的url的方法...
我喜欢蒂默兹的方法,加上一点柠檬味。如果你有机会返回的contentType中的text / html,当你期待JSON,你是最有可能被重定向。就我而言,我只是简单地重新加载页面,然后将其重定向到登录页面。哦,检查一下jqXHR的状态是否为200,这似乎很愚蠢,因为您使用的是错误函数,对吗?否则,合法的错误情况将迫使迭代重载(哎呀)
$.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();
}
});
没有浏览器正确处理301和302响应。实际上,该标准甚至说他们应该“透明地”处理它们,这对于Ajax Library供应商来说是一个巨大的麻烦。在Ra-Ajax中,我们被迫使用HTTP响应状态代码278(只是一些“未使用”的成功代码)来透明地处理来自服务器的重定向。
这真的让我很烦,如果这里有人在W3C中有一些“拉”,我将不胜感激,您可以让W3C 知道我们确实需要自己处理301和302代码...!;)
最终实现的解决方案是对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调用总是在DIV元素内返回HTML,该DIV元素用于替换页面的一部分。另外,我们只需要重定向到登录页面。
我阅读了此问题,并实现了关于将响应HTTP状态代码设置为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
。我发现这种方法要好得多。
You can also hook XMLHttpRequest send prototype. This will work for all sends (jQuery/dojo/etc) with one handler.
I wrote this code to handle a 500 page expired error, but it should work just as well to trap a 200 redirect. Ready the wikipedia entry on XMLHttpRequest onreadystatechange about the meaning of readyState.