我使用$.post()使用Ajax调用servlet,然后使用生成的HTML片段替换用户当前页面中的div元素。但是,如果会话超时,服务器将发送重定向指令,将用户发送到登录页面。在本例中,jQuery用登录页面的内容替换div元素,迫使用户的眼睛看到一个罕见的场景。
如何使用jQuery1.2.6管理Ajax调用的重定向指令?
我使用$.post()使用Ajax调用servlet,然后使用生成的HTML片段替换用户当前页面中的div元素。但是,如果会话超时,服务器将发送重定向指令,将用户发送到登录页面。在本例中,jQuery用登录页面的内容替换div元素,迫使用户的眼睛看到一个罕见的场景。
如何使用jQuery1.2.6管理Ajax调用的重定向指令?
当前回答
我对标题解决方案没有任何成功——它们从未在我的ajaxSuccess/ajaxComplete方法中使用过。我在自定义响应中使用了Steg的答案,但我对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;
}
其他回答
Try
$(document).ready(function () {
if ($("#site").length > 0) {
window.location = "<%= Url.Content("~") %>" + "Login/LogOn";
}
});
把它放在登录页面上。如果它被加载到主页上的一个div中,它将重定向到登录页面。“#site”是位于除登录页面之外的所有页面上的div的id。
使用statusCode选项,如下所示,重定向通常是301、302状态代码。
$.ajax({
type: <HTTP_METHOD>,
url: {server.url},
data: {someData: true},
statusCode: {
301: function(responseObject, textStatus, errorThrown) {
//yor code goes here
},
302: function(responseObject, textStatus, errorThrown) {
//yor code goes here
}
}
})
.done(function(data){
alert(data);
})
.fail(function(jqXHR, textStatus){
alert('Something went wrong: ' + textStatus);
})
.always(function(jqXHR, textStatus) {
alert('Ajax request was finished')
});
后端弹簧@ExceptionHandler。
400和业务相关异常的错误字符串(将在弹出窗口中显示)302和用于浏览器请求的应用程序异常的错误/登录页面的位置标头(由浏览器自动重定向)500/400和错误/登录页面的位置头,用于通过ajax回调重定向ajax请求
通过用户会话将异常详细信息传递到错误页
@Order(HIGHEST_PRECEDENCE)
public class ExceptionHandlerAdvise {
private static Logger logger = LoggerFactory.getLogger(ExceptionHandlerAdvise.class);
@Autowired
private UserInfo userInfo;
@ExceptionHandler(value = Exception.class)
protected ResponseEntity<Object> handleException(Exception ex, WebRequest request) {
HttpHeaders headers = new HttpHeaders();
if (isBusinessException(ex)) {
logger.warn(getRequestURL(request), ex);
return new ResponseEntity<>(getUserFriendlyErrorMessage(ex), headers, BAD_REQUEST);
} else {
logger.error(getRequestURL(request), ex);
userInfo.setLastError(ex);
headers.add("Location", "/euc-portal/fault");
return new ResponseEntity<>(null, headers, isAjaxRequest(request) ? INTERNAL_SERVER_ERROR : FOUND);
}
}
}
private boolean isAjaxRequest(WebRequest request) {
return request.getHeader("x-requested-with") != null;
}
private String getRequestURL(WebRequest request) {
if (request instanceof ServletWebRequest) {
HttpServletRequest servletRequest = ((ServletWebRequest) request).getRequest();
StringBuilder uri = new StringBuilder(servletRequest.getRequestURI());
if (servletRequest.getQueryString() != null) {
uri.append("?");
uri.append(servletRequest.getQueryString());
}
return uri.toString();
}
return request.getContextPath();
}
登录手柄接口
@Service
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Autowired
private UserInfo userInfo;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (userInfo.getPrincipal() == null && !(request.getRequestURI().contains(LOGIN_URL) || request.getRequestURI().contains(FAULT_URL) || request.getRequestURI().startsWith("/app/css"))) {
response.addHeader("Location", LOGIN_URL);
response.setStatus(isAjaxRequest(request) ? BAD_REQUEST.value() : FOUND.value());
return false;
}
return true;
}
}
客户端代码
$.post('/app/request', params).done(function(response) {
...
}).fail(function(response) {
if (response.getResponseHeader('Location')) {
window.top.location.href = response.getResponseHeader('Location');
return;
}
alert(response);
});
我喜欢蒂默兹的方法,稍微加一点柠檬。如果在期望JSON时返回text/html的contentType,则很可能会被重定向。在我的例子中,我只需重新加载页面,它就会被重定向到登录页面。哦,检查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();
}
});
有些人可能会发现以下内容很有用:
我希望客户机被重定向到登录页面,以执行在没有授权令牌的情况下发送的任何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);
}
};
});
就这样。