最近在琢磨前后端分离,难免会碰到跨域问题。
首先弄清楚,跨域指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器施加的安全限制。
何为同源?
URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。
同源策略(是浏览器实施的)
浏览器的同源策略,限制了来自不同源的"document"或脚本对当前"document"读取或设置某些属性 —— 从一个域上加载的脚本不允许访问另外一个域的文档属性。
在浏览器中,<script>、<img>、<iframe>、<link>等标签都可以加载跨域资源,而不受同源限制,但浏览器限制了JavaScript的权限使其不能读、写加载的内容。
另外同源策略只对网页的HTML文档做了限制,对加载的其他静态资源如javascript、css、图片等仍然认为属于同源。
解决方案
对于跨域常见的解决方案一般会想到以下几种方案
- 使用jsonp。
- 修改document.domain跨子域
- iframe
- 反向代理
若想要详细了解以上解决方案,自行百度,本文主要介绍使用跨域资源共享CORS来解决跨域问题
首先CORS需要浏览器和服务器同时支持。
浏览器直接发出CORS请求。在头信息之中,增加一个Origin字段。Origin字段用来说明,本次请求来自哪个源。服务器根据这个值,决定是否同意这次请求。
服务器返回一个正常的http回应。浏览器查看回应的头信息没有包含Access-Control-Allow-Origin字段,检查自己是否所处其中。若不在其中,抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。若在其中,则CORS请求成功。
注意:Access-Control-Allow-Origin字段是html5新增的一项标准功能,因此 IE10以下版本的浏览器是不支持的,因此,如果要求兼容IE9或更低版本的ie浏览器,会导致使用此种方式的跨域请求以及传递Cookie的计划夭折
预检请求
浏览器将CORS请求分为两类: 简单请求和非简单请求。
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json。
例如,下面的前端代码向后台发送了一个非简单请求,因为它制定了'Content-type': 'application/json'
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求。
预检请求的请求方法是OPTIONS,请求的头信息包括两个特殊字段:
- Access-Control-Request-Method
该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。 - Access-Control-Request-Headers
该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
服务器回应的其他CORS相关字段:
- Access-Control-Allow-Methods
该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。 - Access-Control-Allow-Headers
如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。 -
Access-Control-Max-Age
该字段可选,用来指定本次预检请求的有效期,单位为秒。在此期间,不用发出另一条预检请求。