同源策略和跨域
浏览器出于安全考虑,规定两个不同源的页面互相之间不能请求数据,只有相同的源才能请求。但是当我们开发过程中,经常需要两个不同源的页面请求数据,所以就产生了跨域问题
同源策略的主要内容
dom节点:同源策略不允许不同源的两个页面通过JavaScript访问对方的dom节点
网络:限制了xhr,fetch等跨域请求
数据:同源策略不允许不同源的两个页面互相访问浏览器存储,Cookie、IndexedDB和LocalStorage等
什么是相同的两个源
协议、域名、端口一致的称之为同源
同源请求
我们常说的请求是Ajax请求,其实请求图片(<img>),js(<script>) ,css(<link>),都是请求也会有跨域,我们在img标签写的src也是向服务器请求图片到本地,那为什么不会报错呢,那是因为浏览器对与标签的请求没有对于Ajax请求限制的比较厉害。
什么时候发生的跨域
因为浏览器有同源策略,所以产生了跨域问题,没有浏览器根本不可能有跨域问题,所以跨域一定是发生在浏览器这一端的。当我们的页面发出Ajax请求时,这里是不会发生跨域的,服务器能够接收到页面发出的请求,但是当浏览器接收到服务器返回过来的数据之前,出于安全考虑会对响应做出校验,这个时候就有可能会发生跨域问题。
解决跨域的三大方案
CORS
当浏览器接收到后端返回的数据时,会进行校验,而这个校验规则就是cors校验规则。只要我们通过了这个校验规则,也就解决了跨域问题了。
cors将Ajax请求分为两类
简单请求
请求方法为以下之一:get、post、head
请求头只能包含以下简单的、被认为是安全的字段,或者不包含任何自定义头部字段:
-
Accept
-
Accept-Language
-
Content-Language
-
DPR
-
Downlink
-
Save-Data
-
Viewport-Width
-
Width
-
Content-Type(但仅限于以下三个值):
- application/x-www-form-urlencoded:最常见的POST提交数据的方式,用于表单数据的编码。
- multipart/form-data:主要用于文件上传,结合表单使用。
- text/plain:文本格式,较少见,但在需要发送未格式化的字符串时使用。
特点:浏览器在发送这种请求时,会在请求头加入origin字段,当服务器接收到这个请求时会根据该字段的值来判断是否允许跨域请求。如果允许,则会在响应头加上一个Access-Control-Allow-Origin字段,其值可以是源地址,或者是通配符*,表示允许所有源的请求。
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json,或者自定义了头部字段。
特点:
这种请求浏览器在发送真实请求之前会先发送一个option的预检请求,他会在请求头加入origin字段请求源地址,请求方法,请求改动的头部字段。服务器收到后会返回一个允许的源地址、允许的方法、允许的头部headers和最大缓存时间。当这个预检请求通过时,才会发送真实的请求,这个真实的请求和普通请求流程一样。
具体的实现方式是服务器实现了cors接口,就能实现跨域。
JSONP
在没有cors的年代就是用的这种方式,它利用的是浏览器对标签的请求的限制比较小这一特点。但是他有一个缺陷,因为是标签发出的请求,所以只能发送get请求,不能发生post请求。
代理服务器
前面两种方案对服务器均有要求,要求服务器是自己的。当我们请求别人的服务器时,就不能这么做了。所以我们用另一种方案,使用代理服务器。跨域问题只存在浏览器端,服务端之间不存在跨域问题,我们使用一个代理服务器,前端请求到我们的代理服务器,代理服务器帮助我们请求后端的数据,然后通过代理服务器将数据返回给前端,由于代理服务器是我们自己的,所以可以通过以上两种方式CORS或者JSONP来解决跨域问题。