由于这段时间一个项目先后端分别部署在不一样服务器的须要,抽空学习了一下CORS问题,不足之处,欢迎指教.php
什么是CORShtml
CORS是一个w3c标准,全称是"跨域资源共享"(Cross-origin resource sharing),但一个请求url的协议,域名,端口三者之间任意与当前页面地址不一样即为跨域.它容许阅览器向跨源服务器发送XMLHttpRequest请求,从而客服AJAX只能同源使用的限制.web
CORS简介apache
浏览器默认的安全限制为同源策略,即JavaScript或Cookie只能访问同源(相同协议,相同域名,相同端口)下的内容。但因为跨域访问资源须要,出现了CORS机制,这种机制让web服务器能跨站访问控制,使跨站数据传输更安全。CORS须要阅览器和服务器同时支持,目前,主流的阅览器都支持cors。后端
CORS的两种请求方式跨域
浏览器将CORS请求分为两类:简单请求和非简单请求浏览器
一 简单请求缓存
1.1 区分条件:安全
只要知足一下两大条件,属于简单请求:服务器
(1) 请求方法是如下三种方法之一: HEAD GET POST (2)HTTP的头信息不超出如下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
不一样时知足上面两个条件,就是非简单请求
1.2 简单请求的基本流程
浏览器直接发送CORS跨域请求,并在header信息中增长一个Origin字段,代表这是一个跨域的请求。
<script> var url = 'http://www.lishanlei.cn/CorsTest/CorsTest.php'; var xhr = new XMLHttpRequest(); xhr.open('get', url, true); // xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send(); </script>
在上面的代码中以get形式向www.lishanlei.cn进行跨域访问。
上面的头信息Origin字段用来讲明本次请求来自哪一个源(协议+域名+端口)。服务器根据这个值,决定是否赞成此次请求。若是Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应,浏览器收到这个回应发现这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道错了,从而会抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意这种错误没法经过状态码识别,此时HTTP回应的状态码多是200
若是Origin指定的域名在许可范围内,服务器返回的响应会多出几个头信息字段
Access-Control-Allow-Origin:该字段是必须的,其值多是请求时Origin字段的值,也多是一个*,表示接受任意域名请求。
Access-Control-Allow-Credentials:该字段可选,其值类型是布尔型,表示是否容许发送Cookie。默认状况下Cookie不包括在CORS请求中。当设为true时表示服务器明确许可,Cookie能够包含在请求中一块儿发送给服务器。
Access-Control-Allow-Headers:该字段必须,它是一个都好分割的字符串,代表服务器支持的全部头信息字段
1.3 withCredentials属性
默认状况下,CORS请求默认不发送Cookie和Http认证信息,若是要把Cookie发送到服务器,首先要指定Access-Control-Alloe-Credentials字段,另外一方面,须要在AJAX请求中打开withCredentials属性
var xml = new XMLHttpRequest(); xml.withCredentials = true;
若是没有设置该属性为true,即便服务器统一发送Cookie,浏览器也不会发送。
当该属性设置为true时,即须要发送Cookie那么在服务器中Access-Control-Allow-Origin就不能设置成*,必须指定吗明确的与请求一致的域名,同时,Cookie依然遵循同源政策。
二 非简单请求
当不一样时知足区分条件的,就是非简单请求。
2.1 预检请求
非简单请求的CORS请求,会在正式通讯前进行一次Http查询请求,又称预检请求。
浏览器先请求服务器,当前网页所在域名是否在服务器许可名单中以及可使用那些HTTP动词和头信息字段,当客户端获得确定答复时,浏览器才会正式发出XMLHttpRequest请求。
var url = 'http://www.lishanlei.cn/CorsTest/CorsTest.php'; var xhr = new XMLHttpRequest(); xhr.open('PUT', url, true); xhr.setRequestHeader('X-Custom-Header', 'value'); xhr.send();
上面代码中,请求方式是PUT,并发送一个自定义头信息X-custom-Header,但在服务器的头信息中没有包含X-custom-Header,故浏览器报错,只进行了一次预检请求。
设置header中的Access-Control-Allow-Headers字段:
header('Access-Control-Allow-Headers:x-requested-with,content-type,X-Custom-Header');
再次访问
浏览器发现这是一个非简单请求,自动发出一个预检请求,要求服务其确认这样的请求,下面是这个预检请求的HTTP头信息:
预检请求用的请求方法是OPTIONS,表示这个请求是用来询问的。
Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。
Access-Control-Request-Headers:该字段是一个逗号分割的字符串,指定浏览器CORS请求会额外发送的头信息字段。
2.2预检请求的回应
当服务其收到预检请求后,检查了Origin,Access-Control-Request-Method等信息字段后,若是没有问题,则确认容许跨源请求,就能够作出了回应。
Access-Control-Allow-Methods:该字段必须,其值是逗号分隔的一个字符串,代表服务器支持的全部跨域请求的方法。这是为了不屡次预检请求。
Access-Control-Max-Age:该字段是可选的,用来指定本次预检请求的有效期,单位是秒。Access-Control-Max-Age:20,即容许缓存该条回应20秒,再此期间不用发出另外一条预检请求
若是浏览器否认了预检请求,会返回一个正常的HTTP回应,可是没有任何CORS相关的头信息字段。浏览器此时会认定服务器不一样意预检请求,触发一个错误,被XMLHttpRequest的onerror回调函数捕获。
服务器端处理机制
服务器对于跨域请求的处理流程以下:
配置CORS规则
一 apache上配置CORS规则
Apache须要使用mod_headers模块来激活HTTP头设置,默认是激活的,只须要修改Apache配置文件中的/etc/apache2/sites-available/000-default.conf
1 开启模块 sudo a2enmod headers 2 编辑配置文件 sudo vi /etc/apache2/sites-available/000-default.conf 3 在虚拟主机Directory设置下添加 Header set Access-Control-Allow-Origin *
与JSONP的比较
CORS和JSONP都是为了使web浏览器可以跨源请求,使用目的相同,可是比JSONP更强大。JSONP只支持GET请求,而CORS支持全部类型的HTTP请求,不过JSONP的优点在于支持老式浏览器以及能够向不支持CORS的网站跨源请求。
参考博文:http://www.ruanyifeng.com/blog/2016/04/cors.html
https://blog.csdn.net/u014344668/article/details/54948546