背景与思考
请解释并解决一下跨域问题。
关于跨域问题,对于我这个前端来说真的是家常便饭。 浏览某个页面,随着页面的解析和执行, 就会有相应的页面资源/数据请求发生,这时如果接口请求跟当前页面不是同一域名, 那大概率会碰到跨域的问题, 这时候会在浏览器的控制台里会显示类似这样的一种报错:
👆👆👆翻译过来就是: 从“utest.jr.jd.com”域名发送到“https://api.weixin… XMLHttpRequest请求被拒绝了. 原因是: 根据跨域资源共享的规定, 服务器响应头里没有“ Access-Control-Allow-Origin”.因此浏览器阻止解析.
一般看到这种错误, 我就会直接找到服务端, 跟他们说:“哥, 麻烦在返回响应头里, 加一个“ Access-Control-Allow-Origin”的字段, 把值设置为我的域名”. 等服务器设置完成后, 我们再去请求就能正常访问到数据. 跨域问题就算完美解决~
是不是以为就这样就算完了? 虽然遇到的跨域问题已经解决了, 但是并不知道为啥会出现这问题? 比如这三个问题:
-
页面请求到底发出去没有?
-
浏览器是把跨域的请求拦截了? 还是阻止解析请求回来的响应数据?
-
跨域底层原理是什么?
如果这三个问题你心里都有答案了, 那就不用看这下面的啦~
接下来的文字, 都是为了巩固下, 讲明白跨域这件事.
---- 正文 ----
一、CORS是什么?
CORS (Cross Origin Resource Share的简写)称为跨源资源共享.
CORS 是一种基于http 协议头部的机制 , 用于告知浏览器, 是否允许访问加载资源.
关于CORS的描述, 你可能会有点不解. 不过没关系, 迷底会慢慢揭开的. 你只要先记住这两点就行, 1. 跟http协议头机制有关; 2. 跟浏览器有关.
二、CORS的应用场景 - 两种方式
第一种: 直接请求(也叫简单请求)
--- 简单请求的定义-----
如果你的请求符合以下条件, 那就是简单请求, 可以直接发送请求到对应源.
- 请求方式: post, get, head (三选一)
2.Content-Type: (类型也是三选一)
•text/plain
•multipart/form-data
•application/x-www-form-urlencoded
-
请求中没有使用 ReadableStream 对象(这我没用过)
-
至于其他的accept, Accept-Language, Content-Language这些设置(我好像没有设置, 浏览器会取系统默认的)无特殊设置值, 且无新增其他特殊头部的字段.
简单请求, 可以直接发送请求到服务器源. 也就是说客户端的请求发送出去了!(浏览器对简单请求的发送, 没有做拦截.)
客户端的请求发送出到服务端后, 接下来就看服务端的响应信息. 请看下图:
如上图所看到的 , 我们根据http协议头里的 Origin 和 Access-Control-Allow-Origin 的匹配, 就完成了跨域最基本的访问控制.
注意响应头里的““Access-Control-Allow-Origin”
服务端的响应头内“Access-Control-Allow-Origin”, 如果为 * (通配符), 说明任何源都可以访问, 也可以限制为某个固定源访问如: Access-Control-Allow-Origin: www.abc.com
这里有一点需要注意, 关于携带身份认证的请求, Access-Control-Allow-Origin不能简单设置为通配符, 必须指定请求源(服务端可以动态指定可访问的源)
如果服务端的响应头内没有“Access-Control-Allow-Origin”, 浏览器不解析响应数据内容. 并在控制台提示cors错误. (这说明: 浏览器阻止解析响应数据)
第二种: 先option请求,后请求
浏览器先跟服务器进行option请求, 根据结果来决定是否需要发起真实请求 什么样的请求需要先进行option请求?
如果浏览器检测到你的请求不属于简单请求, 或有非http标准的请求头设置, 那浏览器就会先发起option请求,先跟服务端通信, 并发送真实请求头内容. "预检请求“的使用,可避免跨域请求对服务器的用户数据产生未知影响。
- option请求会发送什么呢?
option请求会把真实请求的host, 请求方式, 请求内容等, 都发给服务端, 如下图:
- option请求的响应中的重要信息(字段)需要注意. (因为关系着服务器接不接受你的请求.)
标红的这些信息, 其中Access-Control-Allow-Origin字段的存在, 表示服务器允许, 你可以发起正式请求~
Access-Control-Allow-Headers: 表示请求里的两个头字段, 服务端也接受.
Access-Control-Max-Age: 预检请求可供缓存的时间长短. 单位是秒. 比如上面的值, 表示在 24小时内浏览器不需要再做预检请求了.
Vary: 这个字段是服务器设置的, 主要用代理服务器实现缓存服务,针对静态文件比较合适。所有因子叠加可以提高响应的准确性.
如果在option的请求里, 服务器响应头内没有“Access-Control-Allow-Origin” 字段, 浏览器就会在控制台错误提示跨域错误, 阻止正常请求发送
如果服务器响应头内正常返回后, 再向服务器发送正式请求.
以上就是跨域的全部啦~