仅供自己复习,不保证内容的正确性,有错误请大佬在评论区指出
1. 跨域问题的起因
因为浏览器有 同源策略,他规定了不同的域不能互相访问
1.1 什么是域
- 相同的协议
- 用http协议的网站不能访问使用https协议的网站
- 相同的url
www.baidu.com 不能向www.taobao.com 请求数据www.bilibili.com 不能向game.bilibili.com 请求数据 - 相同的端口
http://abc.com:8080 不能向http://abc.com:8081 请求数据
当满足协议、url、端口都相同时,就可以互传数据了 比如www.bilibili.com/a.html 可以向www.bilibili.com/b.html 请求数据
1.2 传什么数据会有跨域限制
- Cookie、LocalStorage、IndexedDB(跨域的资源不能互相访问存储的数据)
- ajax请求
- js文件(跨域的资源不能互相操纵dom节点)
2. 解决方法
我就想让他们能互相访问
2.1 CORS
CORS是个机制,允许浏览器向服务器发XMLHttpRequest请求
浏览器中的CORS请求分为两种
2.1.1 简单请求
(1) 什么是简单请求
- 请求方法只能是HEAD/GET/POST
- HTTP头信息只能是下面的几个
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只能用这三个值`application/x-www-form-urlencoded`、`multipart/form-data`、`text/plain`
(2) 简单请求流程
- 浏览器发送简单CORS请求,就是直接在http头部添加一个
Origin 字段,用来告诉服务器是哪个域发来的请求 - 服务器收到这个请求,经过判断发现,不能让这个域发送请求。服务器会返回一个正常的HTTP请求,但是,**不会在响应头添加
Access-Control-Allow-Origin **这个字段 - 浏览器收到服务器发回来的请求,发现没有
Access-Control-Allow-Origin 这个字段,浏览器就知道这次CORS请求失败了(但是状态码还是200),然后抛出一个错误,可以用XMLHttpRequest 的onerror 回调函数捕捉到
- 浏览器发送简单CORS请求,就是直接在http头部添加一个
Origin 字段,用来告诉服务器是哪个域发来的请求 - 服务器收到这个请求,经过判断发现,这个域可以发送请求。服务器会在返回的响应头加上这几个字段:
- (必选)
Access-Control-Allow-Origin: *
- 这个字段的内容可以是
* 代表允许所有的域请求这台服务器 - 也可以是刚才请求的域,表示服务器允许了这个域的CORS请求
- (可选)
Access-Control-Allow-Credentials: true
- 让浏览器知道,服务器让不让这个域发送请求的时候带着cookie,让就加上这句话,不让就把这句话删掉
- (可选)
Access-Control-Expose-Headers: stu
- 让浏览器知道,服务器发回去的响应头中包含了自定义的其他字段,如果不写,就算服务器设置了自定义的响应头stu,浏览器也拿不到
2.1.2 非简单请求
(1) 什么是非简单请求
- 请求方法是PUT、DELETE
或者 - HTTP请求头信息中的
Content-Type 是application/json
(2) 非简单请求的流程
- 预检:浏览器会在正式请求前,先发送一个http请求。
- 请求方法为
OPTIONS - 内容有:
- 正式请求的请求方法(GET、DELET)
Access-Control-Request-Method: PUT 请求方法是PUT - 正式请求时会发送哪些自定义的头信息字段
Access-Control-Request-Headers: X-Custom-Header 我有一个自定义的头字段叫X-Custom-Header Origin :是哪个域发来的请求 - 服务器会收到这个预检的请求
- 同意请求:往下看第3点
- 反对请求:响应头啥都不加,浏览器捕捉到错误信息,可以用
XMLHttpRequest 的onerror 回调函数捕捉到 - 如果浏览器允许跨域请求,就会往响应头添加几个字段
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: *
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
Access-Control-Allow-Origin : 跟简单请求的那个一样Access-Control-Allow-Methods :告诉浏览器你可以发送哪个方法来访问这个接口Access-Control-Allow-Headers :跟简单请求的那个一样Access-Control-Allow-Credentials :跟简单请求的那个一样Access-Control-Max-Age :这个预检请求的最大有效时间,过期了就要重新请求一遍,没过期就不用重新请求了 - 浏览器收到预检的结果,如果没通过预检,上面写了。如果通过预检,浏览器就发送这个cors的正式请求。跟简单请求一样,浏览器发过去的请求头会带着
Origin ,浏览器发回来的响应头带着Access-Control-Allow-Origin
|