解决AJAX在用户登录失效后返回登录页面的问题

    对于全站AJAX的应用,当然不存在redirect重定向到登录页面的做法(建议直接返回HTTP Code 401),但是对于某些前后端没有分离的应用,当用户session失效时,后端可能会重定向到登录页面。那对于ajax请求,后端重定向后,返回的ajax内容是一个html页面,怎么办呢?

    总体的思路是在ajax工具的拦截器中做一些特殊的判断。

1、jquery ajax的具体解决办法(示例)如下:

//全局配置
$.ajaxSetup({
    dataType: "json",
    contentType: "application/json",
    cache: false,
    complete: function (jqXHR, status) {
      if(jqXHR.status==200) {
        return;
      }
      if(jqXHR.status==401) {
        var loginPage = 'sys/logout';
        // 处理iframe页面
        if (top) {
          top.location = loginPage
        } else if (parent) {
          parent.location = loginPage
        } else {
          window.location = loginPage
        }
      }
      if(jqXHR.status==403) {
        alert('对不起,你没有权限,若有疑问请联系管理员。<br/>(Access is not allowed. HTTP CODE: 403)');
      }
      if(jqXHR.status==500) {
        alert('请求出错啦,请稍后再试试看。<br/>(Server internal error. HTTP CODE: 500)');
      }
      if(jqXHR.getResponseHeader("content-type") == "text/html") {
        document.write(jqXHR.responseText);
        document.close();
      }
  }
});

代码说明,注意到最后一个if,判断如果ajax返回的是一个页面,则直接document.write显示(如果是登录页,就会直接替换到当前的其他页面)。


2、axios的判断方法如下(原理一样):

axiosInstance.interceptors.response.use(
  response => {
    console.log(response)
    // session 超时....
    if (response.status === 401 
        || response.headers['content-type'] === 'text/html') {

      store.dispatch('FedLogOut')
    } else {
      return response
    }
  },
  error => {
    console.log(error)
    // 若path为登录url,则跳转
    if(error.response.path='/login.html') {
      store.dispatch('FedLogOut')
    }
    return Promise.reject(error)
  }
)

    原理同上面一样,只不过在error处,也做了一个判断。因为后端页面重定向时,在axios中,是不会执行response =>{...}的,但是error=>{...}函数会执行。这个方法官方文档没说明,也是我摸索了十几分钟才试出来的。特此记录分享出来。


    另外,后端也有进一步优化的空间——那就是精确判断Request请求是否为AJAX类型。如果是AJAX请求则未登录时返回401状态码,如果不是AJAX请求,则重定向到登录页面。

    优化空间在于,怎么尽量准确地判断请求是否为AJAX类型?我写了一个Java方法如下:

/**
 * 判断是否为Ajax类型的请求(支持jquery,其他方式未测试过)
 */
public static boolean isAjaxRequest(HttpServletRequest request) {
    String header = request.getHeader("X-Requested-With");
    if (header != null && "XMLHttpRequest".equals(header)) {
        return true;
    }
    return false;
}

    注意看代码注释,很显然,这个方法不够准确,甚至在某些情况下完全失效。

    那怎么办呢,可以根据Header内容来判断,通常AJAX请求的header里面有一些特点的内容,这有助于精确判断请求是否为AJAX类型。另外,判断header中accept的值,如果是类似下面的格式(以application/json开头),通常都是AJAX请求:

// ajax
application/json, text/javascript, */*; q=0.01
application/json, text/plain, */*
// 非ajax
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3


© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号