notes icon indicating copy to clipboard operation
notes copied to clipboard

关于ajax与重定向 or ajax & redirect 30x

Open lanlin opened this issue 7 years ago • 0 comments

场景

前端通过 ajax 发送一个请求到后端服务器的某个 API,API 接收到请求后返回了一个 30X 的重定向。

可能情况

以上的情形可能会发生一系列意想不到的后果,大致列举如下:

  1. 如果重定向的 Location 地址与 ajax 不同源(跨域),受同源策略限制,浏览器不会重定向。

  2. 如果服务器只返回重定向状态码 30X, 但未设置 Location 的值。 那么,浏览器不会重定向,而且你可以从响应的头信息中获取到状态码。

  3. 返回了 30X 状态码,而且设置了 Location 的值,也就是说返回了重定向的地址。 浏览器会自动处理重定向,也就是重新向返回的地址发起一个新请求。

  4. 当返回的状态码是 301、302、303 而且 Location 有值时, 几乎所有浏览器都会删除请求报文内的主体,然后重新向返回的地址发起一个 GET 的新请求。

  5. 当返回的状态码是 307、308 而且 Location 有值时, 请求方法和主体不会被更改,然后重新向返回的地址发起一个的新请求。

  6. 假定 Location 指向的地址是一个后端服务器的 API, 那么最终你的 ajax 请求可能会得到一个 data,比如 json 之类的。

  7. 假定 Location 指向的地址是一个页面,那么最终你的 ajax 得到可能的是那个页面的 html 字符串。

  8. 其他情况...

分析

首先,需要明确的是标准范围内的 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 效果 image

又比如第 5 条中的 307、308 规定,重定向请求必须保持其原有的主体和方法不变。 但是,谁知道呢。。。

建议

如果你的 WEB 应用需要使用 ajax (感觉这是句废话),同时又会出现后端重定向。 那么你可以有两个选择:

  1. 只返回重定向状态码 30X,不设置 Location 的值。 因为浏览器不会重定向,这个时候 ajax 能正常获取到返回的状态码(😓有什么卵用呢?)

  2. 大侠,你还是自定义一个状态码吧,比如 666,然后把重定向地址当做正常的数据返回。 让前端的同学自己去重定向去吧 image

结论

综上所述,ajax 碰到重定向之后,最终取得的结果, 就是完成重定向之后的那个新地址所返回的结果。比如返回给你一个 html, 或者一个 json 等。

所以,应当慎用 ajax 重定向。 或者最好是不用。自己自定义状态码来表示重定向。

请注意,以上的段落一直在说什么浏览器,ajax 之类的。 需知,http 协议和那一大堆的状态码,不是单单只针对浏览器和 xhr 来设定的。 这里只是单纯的讨论浏览器中使用 ajax 时,发生重定向的情况。

lanlin avatar Dec 04 '18 08:12 lanlin