同源和跨域
比较杂的知识点,同源跨域、服务器代理、简单请求非简单请求
为什么要有同源策略
- 本质上是浏览器有cookie这么个玩意,比如移动端app就没有同源限制
- 防止CSRF攻击
如何解决跨域问题
服务器代理
- 开发环境webpack-dev-server
- 生产环境nginx代理服务器部署在同源域名下,转发请求到对应的服务器上(印象中公司项目的配置:某个域名下的某个路径,关联到后端appkey上)
CORS
| 本质上是通过服务端来允许
配置受信任的域名,允许受信任域名的跨域请求
简单请求和非简单请求
满足以下条件就是一个简单请求:
Method: 请求的方法是GET、POST及HEADHeader: 请求头是Content-Type、Accept-Language、Content-Language等Content-Type: 请求类型是application/x-www-form-urlencoded、multipart/form-data或text/plain
当一个请求跨域且不是简单请求时就会发送 OPTIONS 预检请求
而在项目中常见的 Content-Type: application/json 及 Authorization: <token> 为典型的非简单请求,在发送请求时往往会带上 Options
简单请求和非简单请求的CORS校验过程
简单请求
请求头部带上Origin字段,标识发出请求的源地址;
服务端响应头Access-Control-Allow-Origin返回允许请求的源;
浏览器收到服务器的响应后,会检查Access-Control-Allow-Origin允许的源和当前请求源是否一致,若一致,返回对应请求。若不一致,浏览器拦截请求,报跨域错误。非简单请求
比如发送了一个 PUT 请求到 https://api.example.com,并且会带上 Authorization 头
会先发送预检请求:1
2
3
4
5OPTIONS /users/1 HTTP/1.1
Host: api.example.com
Origin: https://www.myapp.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization服务器收到 OPTIONS 请求后,会根据自己的配置来判断是否允许该请求。如果允许,它会返回一个带有 Access-Control-Allow-* 系列头的响应。
1
2
3
4
5
6HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.myapp.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400 // 预检结果的有效期,单位秒Access-Control-Allow-Origin: 明确允许的来源域。Access-Control-Allow-Methods: 明确允许的请求方法。Access-Control-Allow-Headers: 明确允许的请求头。Access-Control-Max-Age: 告诉浏览器预检结果可以缓存多久,在缓存有效期内,再次发送同样的请求就不需要再预检了。浏览器收到服务器的响应后,会检查 Access-Control-Allow-* 头信息是否与自己想要发送的请求匹配。
如果匹配:浏览器认为服务器允许该请求,于是发送真正的 PUT 请求。
如果不匹配或服务器返回错误:浏览器会拦截请求,不会发送真正的请求,并在控制台报一个跨域错误。
JSONP
jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。
1 | function createScriptTag() { |
服务器会返回一个函数调用,类似于 handleData({"data": "value"}) 的内容