参考了文章 你真的了解跨域吗 - 掘金 ,做了简单的笔记和思考。
什么是跨域?
同源策略
协议、域名、端口相同 url,叫做同源。当不同源时:
- Cookie、LocalStorage、IndexedDB 等存储性内容无法读取。
- DOM 节点和 Js对象无法获得
- AJAX 请求发送后,结果被浏览器拦截(注意是 请求发送出去了,也拿到结果了,只是被浏览器截胡了)
跨域
跨域:一个域下的文档或脚本想要去去请求另一个域下的资源。
狭义的跨域:Ajax 发出非同源的请求,触发浏览器的同源策略限制。
跨域的处理方式
这里只讨论狭义的跨域的处理方式,也就是 Ajax 请求导致跨域拿不到数据的问题。这在前端开发中非常常见。
一、使用 JSONP
JSONP(JSON with Padding),是 JSON 的一种使用方法。虽然它的实现原理比较特殊,其实也算不上用到 JSON,但确实能做到拿到数据的效果。举例:
|
|
然后跨域请求的脚本就可以根据请求字符串 callback,拼凑出 getData({ name: 'Bolt' }) 这样的字符串作为请求脚本的内容。这样,我们就实现了跨域请求。但这种方法已经过时了。
缺陷是只能发出 get 请求。
二、CORS(跨域资源共享)
简单请求 和 非简单请求
-
简单请求:跨域请求时,直接带上 origin 头。(HTML Form 在不依赖脚本的情况下可以发出的请求)
-
非简单请求:跨域请求时,先额外发送 OPTIONS 请求来确定服务器是否允许跨域请求,再发送真正的请求。这个额外的请求成为称为 preflight 预检请求。

preflight 请求的内容:

- access-control-request-headers:真正请求中使用的请求方法
- access-control-request-headers:超出简单请求允许范围的头字段。
服务器的 CORS 头字段
比如 github 的公共接口,请求回来的响应头中,就有 access-control-allow-origin: *,意思是任何请求源都可以请求,浏览器不必阻拦返回的数据。
https://api.github.com/search/users?q=fstar

- Access-Control-Allow-Origin:允许资源访问的 origin
- Access-Control-Allow-Methods:运行资源访问可以使用的请求方法(preflight 请求可能会返回)。
- Access-Control-Allow-Credentials:值为 true 表示可以发送 cookies。(xhr 请求要设置
xhr.withCredentials = true)此时 Cookies 依旧遵循同源策略,只有用服务器域名设置的Cookie才会上传。只能设置为 ture,或去掉这个头字段。 - Access-Control-Allow-Headers:允许使用的不在简单请求内的请求头字段。
- Access-Control-Max-Age:预检请求的缓存时间长度,如
1800表示 1800 秒,过期发送同样的请求,就不需要再发预检请求了。
三、使用代理
同源策略只对浏览器生效,使用代理可以解决跨域问问题。
在进行开发中,我们通常会使用脚手架的代理功能,比如 webpack-dev-server、Vue 和 React 脚手架集成的代理功能。
Ajax 发起的是同源的请求,但在符合配置规则(比如 /api 开头)的情况下,会转发给真正的服务器拿到数据再转发回来。这样浏览器的请求就是同源的,不会出现跨域问题。
至于部署,常常会使用 Web 服务器进行方向代理,和开发的请求转发效果差不多。