跨域问题
同源策略
同源策略(SOP Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也是最基本的安全功能,如果缺少同源策略,浏览器很容易受到 XSS、CSFR 等攻击。所谓同源是指协议+域名+端口三个要素均相同(即使两个不同的域名指向同一个 IP 地址也算跨域)。
跨域指浏览器默认是不允许当前页面所在的源去请求另一个源的数据。因此,一旦有这样的需要,就应当去解决跨域问题。(毕竟,有些时候的确会从不同地方拿数据,很多服务也不一定跑在同一个端口)
下面介绍跨域问题的一些主流的解决方式:
CORS
CORS 意为跨域资源共享,是目前最主流的跨域解决方案。目前浏览器基本都支持 CORS,服务端也有相应的工具来支持 CORS。
CORS 不需要改变以前的业务逻辑,只需浏览器在请求中携带一些头信息,我们需要以此判断是否允许其跨域,然后在响应头中加入一些信息即可。这一般通过过滤器完成即可。
一般来说,浏览器会将请求分为两类:简单请求和复杂请求。一个请求为简单请求,需要满足以下条件:
- 请求方法为
GET
、HEAD
或者POST
- 头字段只有这几种:
Accept
、Accept-Language
、Content-Language
和Last-Event-ID
和Content-Type
,并且Content-Type
只限于三个值application/x-www-form-urlencoded
、multipart/form-data
和text/plain
。
其余请求为复杂请求。
简单请求
如果浏览器发现是简单请求,那么会在请求头中带上 Origin
,指出当前的请求来自哪个域。服务器可以根据这一字段判断是否允许跨域。如果允许,那么服务器会在请求头中加入:
Access-Control-Allow-Origin: <Origin>
Access-Control-Allow-Credentials: true
(代表是否允许传 Cookies)Content-Type: text/html; charset=utf-8
浏览器可以根据这些来判断这一请求是否违反了 CORS。
复杂请求
复杂请求会在实际发送请求之前增加一次 HTTP 请求,称为预检请求。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest
请求,否则就报错。服务端进行判断后,除了在请求头中加上上面简单请求的三个字段,还会添加以下字段:
Access-Control-Allow-Methods
(代表允许的动词)Access-Control-Allow-Headers
(代表允许携带的头)Access-Control-Max-Age
(缓存,这次预检请求的有效期)
当下次发送同类请求时候,如果没有超出有效期,那么就不必要再次发送预检请求,直接传复杂请求就好。
其他
- WebSocket
- iFrame:当二级域名相同的时候,设置
document.domain
即可使用JavaScript
创建一个iFrame
对象,然后用它进行发请求。 - JSONP:只支持
GET
,相当于<script src='https://xxx.xxx.xx?key=value&callback=xxx' \><script>
- 客户端代理、服务端反代。