一、ajax 302


ajax用于异步获取服务器数据,但是某天有这么一个使用场景:

> 基于安全考虑,登录的用户的信息失效时,系统的所有ajax接口都由服务器直接重定向到系统的登录页面,此时登录页面与系统属于同一个域;

于是否,使用ajaxComplete的方法为系统所有ajax统一设置请求完成后的回调,判断其http的status code是否为302,类似于下面代码:

$(document).ajaxComplete(function(e, xhr, settings){
var _location;
console.log(xhr);
if(xhr.status === 302){
_location = xhr.getResponseHeader("Location");
if(_location) {
location.assign(_location);
}
}
}); //获取数据的接口
$.ajax({
url: "/api/fetch.html"
}).always(function(ret){
console.log(ret);
});

可是测试结果显示,ajax的回调在重定向之后死活没有执行,直至获取重定向后的请求才会执行ajax的回调,也就是说重定向后的内容作为ajax的接口内容来响应。此时可以看到浏览器控制台输出的ret内容不是json字符串,实际上为系统重定向到登录页面的html字符串。


为什么会出现这样的结果呢?

在stackoverflow上可以找到讨论的答案:

> You can't handle redirects with XHR callbacks because the browser takes care of them automatically. You will only get back what at the redirected location.

也就是说,重定向是由浏览器自动透明的完成的。所以服务器将302响应发给浏览器时,浏览器并不是直接处理ajax的回调,而是先执行302重定向。这就是上面例子中为什么获取不到xhr.status为302的值。

一个ajax请求的重定向大致流程是这样的:

ajax --> browser --> server --> 302 --> browser(redirect) --> server --> browser --> ajax callback

注意,上面ajax获取不到xhr的status是有一个前提:即,服务器为response设置了*Location* header。

因为,浏览器在发现Location的header时就会自动跳转到Location所指定的URL地址,类似于用js来进行重定向;不过这个重定向只有浏览器知道。

所以,在ajax接口返回302时,而没有设置Location的header时,这个xhr的status值还是能获取到的,下图是在浏览器控制台测试的结果:

可以看到服务器给response的header添加了Location1的header,浏览器并不认识,所以不会重定向,此时或可以获取xhr的status为302

二、ajax 302跨域


随着公司业务的发展新的情况出现了,公司要将登录认证统一到某台公共的服务器上,这时,失效的用户在ajax获取数据时状态失效而被重定向到登录页面;由于当前系统与登录页面不同域,而XHR不允许跨域访问数据,所以ajax的302也存在跨域问题。(不像页面之间重定向不存在这个问题,你可以访问当前系统的某个页面,服务可以重定向到www.baidu.com而不会有跨域问题)。

这时,由于存在跨域,浏览器不会进行重定向;但是能否通过上面的代码来用JavaScript进行重定向呢?

抱歉,同样不可以;这时通过ajaxComplete方法获取到的xhr的status值,发现其值为0,Location的header为null;所以这种办法行不通。更可取的方法可以是这样:

首先不要在服务器端进行重定向;然后通过接口的形式或者在response添加一个自定义header来区分重定向信息;最后由JavaScript来进行重定向

三、xhr status为0的问题


翻看W3C文档,发现xhr的status值由以下三个步骤来决定:

The status attribute must return the result of running these steps:

  1.  If the state is UNSENT or OPENED, return 0.

  2.  If the error flag is set, return 0.

  3.  Return the HTTP status code.

第二条的error flag:The error flag indicates some type of network error or fetch termination. It is initially unset.

通过上面得知:

在调用xhr的open方法还没有调用send方法,或者xhr出错了(如跨域就会发生网络错误)都会导致xhr state为0的情况

最常见的两种xhr status为0的情况:

  • ajax发送后还没有得到响应前立即刷新浏览器,这时ajax就会被浏览器给丢弃了,会返回status code为0;这主要发生在form表单的提交用ajax来提交,而没有阻止表单提交的默认行为,导致页面刷新,这时ajax发出了,但页面刷新; 其实ajax能得到xhr的status只不过值为0;

  • xhr跨域,包括异步请求跨域和302跨域的情况,这时会出现xhr status为0的情况

参考文献

jQuery ajax 302跨域的更多相关文章

  1. jquery ajax jsonp跨域调用实例代码

    今天研究了AJAX使用JSONP进行跨域调用的方法,发现使用GET方式和POST方式都可以进行跨域调用,这里简单分享下,方便需要的朋友 客户端代码 复制代码 代码如下: <%@ Page Lan ...

  2. jquery ajax 无法跨域调用的解决办法

    今天要用到jquery ajax 跨域调用,但是ajax是禁止跨域调用的,所以只能先在php文件使用函数取得跨域的值,然后用ajax调用本地php文件.

  3. 解决jquery ajax在跨域访问post请求的时候,ie9以下无效(包括ie9)的问题

    最近在做项目的时候遇到一个问题,就是跨域请求ajax的时候ie9以下的浏览器不可以访问,直接执行error里面的代码,但是也不报错,就上网查了查,发现了一个很好用的方法,在这里记录一下,也希望可以帮到 ...

  4. jquery ajax在跨域访问post请求的时候,包括ie9以下的浏览器无效,其他浏览器正常

    最近做的一个项目,原先没有要求兼容IE9以下,所以在写代码的时候也没有打开IE9以下去测试,这两天要去做IE9以下的兼容,在IE9以下打开本地的项目发现数据请求不成功,而通过发布道服务器上的链接打开是 ...

  5. jquery ajax CORS 跨域訪问 WebService

    JS代码: var word = document.getElementById("word").value; $.ajax({ type: "POST", c ...

  6. jquery ajax在跨域访问post请求的时候,ie9以下无效(包括ie9)

    1. 设置浏览器安全属性,启用[通过域访问数据源]选项,如图:

  7. JQuery+ajax+jsonp 跨域访问

    Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料. 关于Jsonp更详细的资料请参考http://baike.baidu.com/ ...

  8. PHP 支持 JQuery 的 JSONP 跨域访问

    Jquery Ajax进行跨域时需要使用JSONP,但JSONP格式和JSON格式是有区别的,如果直接返回JSON格式就会报错 首先将原有的Jquery代码中的dataType改成“jsonp”,具体 ...

  9. jQuery的ajax jsonp跨域请求

    了解:ajax.json.jsonp.“跨域”的关系 要弄清楚以上ajax.json.jsonp概念的关系,我觉得弄清楚ajax是“干什么的”,“怎么实现的”,“有什么问题”,“如果解决存在的问题”等 ...

随机推荐

  1. .NET发送邮件的方法

    整理一下,在.NET中发送邮件的一个方法,代码如下: public static string Net_Email(string strSendto, string strCC, string str ...

  2. Linux学习笔记:Shell脚本学习

    概念 真正能够控制计算机硬件(CPU.内存.显示器等)的只有操作系统内核(Kernel),图形界面和命令行只是架设在用户和内核之间的一座桥梁. 由于安全.复杂.繁琐等原因,用户不能直接接触内核(也没有 ...

  3. Unity3d 插值Lerp与Slerp

    Lerp Lerp表示线性插值. Slerp 球形插值在Vector3.Quaternion等类都有使用,一般多在Quaternion的旋转操作时使用.

  4. Router types

    Inq-n. Flits are stored at the input of the router. Each input unit is connected to the switch by as ...

  5. dj 分页器组件

    django内置的分页器组件,能够帮我们实现对查询的数据进行自动分页,并返回分页对象 from django.core.paginator import Paginator, EmptyPage Pa ...

  6. BZOJ 3744 Gty的妹子序列 (分块 + BIT)

    3744: Gty的妹子序列 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1931  Solved: 570[Submit][Status][Dis ...

  7. JS中的计时器事件

    JS可以实现很多java代码不易完成的功能.这里学习一些js中的计时器事件. JavaScript 一个设定的时间间隔之后来执行代码,称之为计时事件. 主要通过两个方法来实现: 1.setInterv ...

  8. 学以致用十七-----shell脚本之比较数字和字符串及if else

    非常需要注意的是shell脚本对空格要求非常严格, 如: 比较字符串   (不能用于比较字符串) 以上这种写法会报错 因此比较字符串不用 单中括号 [ ] -----------------有误 而是 ...

  9. PuTTY乱码问题解决办法

    原文链接:http://www.henshiyong.com/archives/403.html 使用PuTTY 时,遇到了乱码问题,查看了别人介绍的信息,解决掉了. 方法其实很简单,现在分享出来. ...

  10. 防火墙内JVisualVM连接jstatd解决方案

    jstatd启动后会打开两个端口,其中一个端口可通过参数“-p”指定,如果不指定默认为1099,另一个是一个随机端口,不能参数指定: # netstat -lpnt|grep jstatd tcp   ...