跨域的分类
1. 域名不同
2. 域名相同,端口不同
3. 二级域名不同
引入跨域限制的原因
处于安全考虑。例如,浏览淘宝的时候访问了这个网站,这个网站利用ajax可能访问淘宝进行操作,这时候会拿着你的淘宝的cookie作为token去做坏事。
跨域的解决方案
1. jsonp
原理:利用script标签实现
需要服务的支持
只能get请求
2. nginx反向代理
思路:利用nginx反向代理把跨域为不跨域,支持各种请求方式
缺点:需要在nginx进行额外配置,语义不清晰
3. CORS
请求分为两类
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
当浏览器发现ajax请求属于简单请求,就会在请求头中添加Origin字段,如Origin:http://manage.leyou.com
Origin中会指出当前请求属于哪个域(协议+域名+端口)。服务会根据这个值决定是否允许其跨域。
如果服务器允许跨域,需要再返回的响应头携带以下信息:
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
在本次遇到的问题,实际上发起了一次简单的请求,在Response Headers中可以看到
2. 特殊请求
不符合简单请求的会被浏览器判断为特殊请求,例如PUT请求。
预检请求
特殊请求会在正式通信之前,增加一次HTTP查询请求,成为“预检”请求
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和head信息字段。只有得到肯定回复,浏览器才会发出正式的XMLHTTPRequest请求,否则就报错
一个预检请求样板
OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
预检请求报文中的 Access-Control-Request-Method 首部字段告知服务器实际请求所使用的 HTTP 方法;Access-Control-Request-Headers 首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。
服务器收到预检请求,如果许可跨域,会发出响应:
分析:
除了简单请求中会返回的以下两个头
Access-Control-Allow-Origin: http://manage.leyou.com
Access-Control-Allow-Credentials: true
还有
Access-Control-Allow-Methods: 允许访问的方式
Access-Control-Allow-Headers: 允许携带的头
Access-Control-Max-Age: 本次许可的有效时长,单位是秒,过期之前的ajax请求就无需再次进行预检了