在我们日常开发中,跨域请求是不可避免的事情,本文主要是结合猪八戒的技术体系,介绍几种常见的跨域问题的表现,排查问题的思路。
一、跨域的概念
简单介绍一下跨域的基本概念,不满足浏览器同源安全策略的请求即是跨域,同源安全策略因不同浏览器,以及不同版本有所不同,同源的含义通常为 协议(http\https),域名( www.taobao.com )和端口号( 80 , 8080 )都相同。
二、允许跨域的设置
允许跨域设置,主要是由服务器端处理,在猪八戒技术体系里即是在node层,分为两种情况,简单请求和复杂请求。
1、简单请求
不会触发 CORS 预检请求的请求一般称为简单请求,且必须满足以下所有条件:
条件1:使用下列方法之一:
GET
HEAD
- POST
条件2:Content-Type 的值仅限于下列三者之一:
text/plain
multipart/form-data
- application/x-www-form-urlencoded
条件3:不能手动设置以下集合之外的请求头:
accept
accept-language
- content-language
- content-type
条件4:请求中的任意 XMLHttpRequest 对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。 (一般都满足)
条件5:请求中没有使用readableStream对象 (一般都满足)
满足简单请求的跨域只需要node层在接口响应的时候设置以下头部信息即可:
2、复杂请求
不符合以上条件的请求就肯定是复杂请求,且肯定会触发 CORS 预检请求 ,比如常见的POST请求:Content-Type为application/json。
node层需做以下配置,以utopia举例;
配置预检请求:
接口请求设置:
特别注意:
"Access-Control-Allow-Origin"的值最合适的是配置白名单,因为headers里的Origin某些客户端在特定情况下请求的时候不会携带,如果设置为"*",根据w3c标准"Access-Control-Allow-Credentials"就不能设置为true,主流浏览器都会遵循此标准,防止泄漏隐私数据,在这种情况下会拒绝将数据返回给js, 如果不想配置白名单那么麻烦,常用的方式是通过请求参数将origin传递到utopia服务器。
三、常见的跨域表现和原因
1、因为未设置允许跨域,不满足浏览器同源安全策略
通常看到的跨域的表现,就是下面这种报错:
重点的报错信息是这个, "No 'Access-Control-Allow-Origin' header is present on the requested resource" ,请求的资源上不存在访问控制允许源标头,这种就直接排查接口的实现是否设置了允许跨域,如果确定允许跨域的设置没有问题,继续看下面的可能情况
注意: 排查允许跨域设 置的时候,要先明确当前请求是简单请求还是复杂请求,两种请求方式的跨域设置有差异。
2、"Access-Control-Allow-Origin"的值不正确
值不正确主要是两种情况: 一种是“Ac cess-Con trol-Allow-Origin”的值 与当前请求的站点不一样 , 比如:
当前请求的站点是 “http://local.test.zbjdev.com:3100”与接口设置的允许的跨域访问的站点“https://chongqing.zbj.com”不 相等,自然就会访问失败,这种检查一下配置就行了
另外一种就是“Access-Control-Allow-Origin”的值格式不正确,比如:
和第一种情况的报错非常相似,但原因其实截然不同,“Access-Control-Allow-Origin”的值应该仅仅包含站点信息,不包含任何路径信息,' http://local.test.zbjdev.com:8300/ '就是带上路径了,正确语法如下:
如果排除是"Access-Control-Allow-Origin"的值不正确导致的问题,请看下面的情况。
3、访问接口被重定向了,但重定向的url不支持跨域访问
这种情况常见因为接口做了登录限制,但请求的时候没有带上用户登录信息导致
报错信息里面会有关键的“redirected from”等重定向的信息,需要去排查是不是请求的时候是否存在有效的登录cookie,或者是客户端在请求的时候没有带上cookie信息,客户端请求带cookie配置以axios库举例:
特殊情况: 如果是复杂请求,浏览器会进行一次 CORS 预检请求 ,预检请求是不会携带cookie的,确认是这种情况,就不要对预检请求做登录限制。
4、接口只在代码正常执行的逻辑里设置了允许跨域,代码执行异常的响应没有设置允许跨域
这种情况非常隐蔽,在node层我们可以设置各种各样的中间件来抽离一些公共逻辑,但是公共逻辑的异常报错响应,一般是不会有跨域相关的设置的,比如这段示范代码:
在这段代码的逻辑里面,会有一个“paramsCheck”的中间件对请求参数“text”是否为空做校验,“text”不为空的情况下,在最后响应客户端的请求的时候会进行允许跨域的设置,不会有问题,但如果“text”为空的时候,“paramsCheck”中间件会拦截,响应客户端,但是并没有进行允许跨域的设置,就会导致前端报错,且报错信息即是普通跨域的样子,并且因为浏览器同源安全策略,在chrome调试工具的network面板无法看到服务端任何响应信息,具体表现可见下面的附图:
我们再看另外一段示范代码,是常见的另一种没有在异常逻辑进行允许跨域设置,导致出现跨域报错的代码:
四、总结
经常遇到的跨域情况,我们可以按照以下这个思路去进行排查:
希望以上内容能对有需要的人有所帮助