关于ajax与重定向 or ajax & redirect 30x
场景
前端通过 ajax 发送一个请求到后端服务器的某个 API,API 接收到请求后返回了一个 30X 的重定向。
可能情况
以上的情形可能会发生一系列意想不到的后果,大致列举如下:
-
如果重定向的 Location 地址与 ajax 不同源(跨域),受同源策略限制,浏览器不会重定向。
-
如果服务器只返回重定向状态码 30X, 但未设置 Location 的值。 那么,浏览器不会重定向,而且你可以从响应的头信息中获取到状态码。
-
返回了 30X 状态码,而且设置了 Location 的值,也就是说返回了重定向的地址。 浏览器会自动处理重定向,也就是重新向返回的地址发起一个新请求。
-
当返回的状态码是 301、302、303 而且 Location 有值时, 几乎所有浏览器都会删除请求报文内的主体,然后重新向返回的地址发起一个 GET 的新请求。
-
当返回的状态码是 307、308 而且 Location 有值时, 请求方法和主体不会被更改,然后重新向返回的地址发起一个的新请求。
-
假定 Location 指向的地址是一个后端服务器的 API, 那么最终你的 ajax 请求可能会得到一个 data,比如 json 之类的。
-
假定 Location 指向的地址是一个页面,那么最终你的 ajax 得到可能的是那个页面的 html 字符串。
-
其他情况...
分析
首先,需要明确的是标准范围内的 30X 重定向,都是浏览器自行完成的。 也就是说,浏览器在接收到服务器返回的重定向状态码后,会马上进行重定向。 不论你之前发起的请求是通过 ajax (xhr), 还是传统的 form 表单请求,还是点击超链接等等。
而 ajax 请求碰到返回重定向的不同之处,在于,浏览器先完成重定向, 然后取得重定向返回的结果,再将结果返回给 ajax 的回调。其处理顺序大致如下:
ajax -> browser -> server -> 30X ->
browser(redirect) -> server -> browser -> ajax callback
至于为什么有那么多不同的重定向状态码,其实也是为了规范。 有的是临时重定向,有的是永久重定向。但是,浏览器厂商是不是遵守标准? 两个字:呵呵~
比如 301、302的标准是禁止将 POST 方法改变成 GET 方法的,但现实是, 各个浏览器都是如第 4 条情形中的那样,直接把报文主体丢了,给你换成 GET...
303 倒是明确规定,重定向时就会使用 GET 方法,所以基本上浏览器都有 303 效果

又比如第 5 条中的 307、308 规定,重定向请求必须保持其原有的主体和方法不变。 但是,谁知道呢。。。
建议
如果你的 WEB 应用需要使用 ajax (感觉这是句废话),同时又会出现后端重定向。 那么你可以有两个选择:
-
只返回重定向状态码 30X,不设置 Location 的值。 因为浏览器不会重定向,这个时候 ajax 能正常获取到返回的状态码(😓有什么卵用呢?)
-
大侠,你还是自定义一个状态码吧,比如 666,然后把重定向地址当做正常的数据返回。 让前端的同学自己去重定向去吧

结论
综上所述,ajax 碰到重定向之后,最终取得的结果, 就是完成重定向之后的那个新地址所返回的结果。比如返回给你一个 html, 或者一个 json 等。
所以,应当慎用 ajax 重定向。 或者最好是不用。自己自定义状态码来表示重定向。
请注意,以上的段落一直在说什么浏览器,ajax 之类的。 需知,http 协议和那一大堆的状态码,不是单单只针对浏览器和 xhr 来设定的。 这里只是单纯的讨论浏览器中使用 ajax 时,发生重定向的情况。