Open xuallen opened 3 years ago
前段时间接手了一个项目,在代码中看到了这样的一段代码:
if ( isHTML(data) && response.request.responseURL?.indexOf(CAS_PREFIX) > -1 ) { window.location.href = response.request.responseURL; }
主要的作用就是当后端响应的内容是html的时候,跳转到登录页面。这种方案让我感觉有点别扭,于是具体了解了这段代码出现的原因。
功能的核心在于用户鉴权,后端设想的方案是:当前端发起接口请求,后端识别到用户未登录的时候,就会给前端响应302的状态码,以为很方面,前端不用处理就直接跳转到了登录页面。
然而,他们不知道的是,前端发起的ajax请求,并不能直接跳转,甚至连302状态码都捕获不到。
HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599)。
更多状态码:传送门
我们知道,浏览器对于不同的状态码,会有不同的行为。那当返回302的时候,浏览器会有什么样的反应呢?
重定向,顾名思义,就是把请求重新指向了一个新的地址。
当浏览器发起一个请求,服务端返回了302状态码,这时候浏览器会根据响应头中的location字段,重新发起一个请求。当重定向次数过多的时候,浏览器会抛出ERR_TOO_MANY_REDIRECT的异常。
ERR_TOO_MANY_REDIRECT
请求分两种情况:
前面提到的,服务端觉得返回302很方便,大概是以为ajax也会跳转到新页面吧。
使用fetch Api进行请求的时候,可以通过redirect参数配置如何处理重定向。
redirect
redirect可选的值有三个:
follow
error
TypeError: Failed to fetch
manual:手动处理重定向
manual
在Chrome中默认使用follow(Chrome 47之前的默认值是manual)。
当我们设置成manual时,如果发生了重定向,会拿到type为opaqueredirect的response:
opaqueredirect
{ "body": null, "bodyUsed": false, "headers": {}, "ok": false, "redirected": false, "status": 0, "statusText": "", "type": "opaqueredirect", "url": "https://xxx.com", }
一般来说,我们是不需要手动处理重定向的,因为你不知道这个重定向是否是就是因为未登录才产生的重定向。
当用户未登录时,我们除了302状态码之外,可以选择使用401或403状态码,这样至少前端可以捕获到,并作出跳转的处理。
在项目中,我们和服务端的协议格式基本都是json,响应的内容格式如下:
{ "code": 0, "data": null, "msg": "ok" }
一般来说,服务端都会响应200的http状态码,然后使用body里面的code字段标识业务异常。所以当用户未登录时,响应以下内容,也是不错的选择:
{ "code": 40401, "data": "https://login.xxx.com", "msg": "Unauthorized" }
如果的确要考虑自动跳转的场景,可以在服务端区分一下请求是来源于页面请求还是ajax请求,然后根据不同的请求响应不一样的内容即可。比如以Express为例:
// The user needs to login again if (req.xhr) { res.status(200).json({ code: 40401, data: 'https://login.xxx.com', msg: "Unauthorized" }) } else { res.redirect('https://login.xxx.com') }
另外,我们还可以利用Accept请求头来区别响应。
Accept
Accept 请求头用来告知(服务器)客户端可以处理的内容类型,这种内容类型用MIME类型来表示。借助内容协商机制, 服务器可以从诸多备选项中选择一项进行应用,并使用 Content-Type 应答头通知客户端它的选择。浏览器会基于请求的上下文来为这个请求头设置合适的值,比如获取一个CSS层叠样式表时值与获取图片、视频或脚本文件时的值是不同的。
常见的,直接在浏览器导航栏打开一个地址,Accept的值大概会是Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9;ajax请求,会是:Accept: application/json, text/javascript, */*; q=0.01。其中;q= (q因子权重)的值代表权重。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept: application/json, text/javascript, */*; q=0.01
;q= (q因子权重)
更多Accept介绍:传送门
最后,点一下题。当后端给你返回了302,在他们看来,应该是这样的:
然而,在前端看来,却是这样的:
以上,简单探讨了常见又不常处理的状态码302,如有错漏,欢迎指正!
前言
前段时间接手了一个项目,在代码中看到了这样的一段代码:
主要的作用就是当后端响应的内容是html的时候,跳转到登录页面。这种方案让我感觉有点别扭,于是具体了解了这段代码出现的原因。
功能的核心在于用户鉴权,后端设想的方案是:当前端发起接口请求,后端识别到用户未登录的时候,就会给前端响应302的状态码,以为很方面,前端不用处理就直接跳转到了登录页面。
然而,他们不知道的是,前端发起的ajax请求,并不能直接跳转,甚至连302状态码都捕获不到。
常见状态码
303:硬糖少女4:阿森纳更多状态码:传送门
我们知道,浏览器对于不同的状态码,会有不同的行为。那当返回302的时候,浏览器会有什么样的反应呢?
浏览器处理302状态码
重定向,顾名思义,就是把请求重新指向了一个新的地址。
当浏览器发起一个请求,服务端返回了302状态码,这时候浏览器会根据响应头中的location字段,重新发起一个请求。当重定向次数过多的时候,浏览器会抛出
ERR_TOO_MANY_REDIRECT
的异常。请求分两种情况:
前面提到的,服务端觉得返回302很方便,大概是以为ajax也会跳转到新页面吧。
阻止ajax重定向
使用fetch Api进行请求的时候,可以通过
redirect
参数配置如何处理重定向。redirect
可选的值有三个:follow
:自动重定向error
:如果产生重定向将自动终止并且抛出一个错误TypeError: Failed to fetch
manual
:手动处理重定向在Chrome中默认使用follow(Chrome 47之前的默认值是manual)。
当我们设置成
manual
时,如果发生了重定向,会拿到type为opaqueredirect
的response:一般来说,我们是不需要手动处理重定向的,因为你不知道这个重定向是否是就是因为未登录才产生的重定向。
如何处理未登录跳转的问题
当用户未登录时,我们除了302状态码之外,可以选择使用401或403状态码,这样至少前端可以捕获到,并作出跳转的处理。
在项目中,我们和服务端的协议格式基本都是json,响应的内容格式如下:
一般来说,服务端都会响应200的http状态码,然后使用body里面的code字段标识业务异常。所以当用户未登录时,响应以下内容,也是不错的选择:
如果的确要考虑自动跳转的场景,可以在服务端区分一下请求是来源于页面请求还是ajax请求,然后根据不同的请求响应不一样的内容即可。比如以Express为例:
另外,我们还可以利用
Accept
请求头来区别响应。常见的,直接在浏览器导航栏打开一个地址,Accept的值大概会是
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
;ajax请求,会是:Accept: application/json, text/javascript, */*; q=0.01
。其中;q= (q因子权重)
的值代表权重。更多
Accept
介绍:传送门后语
最后,点一下题。当后端给你返回了302,在他们看来,应该是这样的:
然而,在前端看来,却是这样的:
以上,简单探讨了常见又不常处理的状态码302,如有错漏,欢迎指正!