浏览器默认是不允许XMLHttpRequest(ajax)发送请求到其他网站(跨域)的,
比如a网站的javascript想要从b网站获取数据时就会被浏览器拦截。这也是为了安全考虑,如果不做限制的话,
a网站的js 请求b网站时默认会把b网站的cookie带上,a网站就可以以b网站的登录信息(b网站的cookie)去攻击b网站。
但是实际应用中,有时候确实需要跨域请求的,跨源资源共享 (CORS)就是用来解决实现这种功能的。
CORS是http协议的一部分,需要浏览器和web服务器共同支持,目前绝大多数的浏览器和服务器都已支持。
CORS把请求分成两类,简单请求和非简单请求
简单请求:
同时满足下面两个条件就是简单请求
(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.浏览器发现ajax的请求时跨域的,会在请求头里面添加一个origin字段,值为当前域地址(不包含路径)。
2.服务器拿到请求后会正常处理请求,然后再检查请求的头,发现origin,就知道这是跨域的请求,会检查origin的域名是否在服务器的许可列表里,如国在就在响应头添加一个Access-Control-Allow-Origin字段,值就是origin的值。如果不在就不设置Access-Control-Allow-Origin这个头。然后返回相应
3.浏览器收到响应,知道这是个跨域的响应,检查响应头里是否有Access-Control-Allow-Origin,如果没有就立即报错并停止执行ajax的代码,如果有,并且值为自己的域名,或者为通配符*,就正常处理。
注意在这种简单请求里,浏览器会正常发送请求的,服务器也会正常处理请求,唯一可能被拦截的就是最后浏览器收到响应后是否会处理,如果没有Access-Control-Allow-Origin这个头信息,就会停止处理。所以这个过程请求响应一定还是会被处理的。
非简单请求
如果请求不符合简单请求的条件,就是非简单请求。这种请求一般会修改服务器上的资源,所以处理上比较严格。
非简单请求过程如上图,步骤为:
- 浏览器发现ajax的请求是跨域的,并且是非简单请求,为了服务器的安全,不会像简单请求一样直接发送请求,而是会先发送一个OPTIONS的请求给服务器,询问服务器网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错,这个请求里也会有origin头信息。
2.服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应
3.浏览器收到服务器的“预检请求”响应后,检查头信息里的Access-Control-Allow-Origin字段,如果为当前的域名或者为通配符*, 则知道这个跨域请求可以进行,就会正常发送用户的请求,否则为不可进行,拦截用户的请求
从上面的过程可以看到,无论是简单还是非简单请求,CORS的过程都需要服务端和浏览器共同配合,
请求只要通过了浏览器的验证,服务器总是会正常处理。所以如果我们使用代码怕虫来发送请求,就不会有跨域请求的问题,总能成功。
另外注意到,简单请求服务器总是会处理,拦截只发生在浏览器处理服务器响应过程中,在chrome的network里还是可以看到服务器返回的正常数据,并且响应码200正常。这就警示我们,不要在简单类型的请求里更新重要数据,否则跨站cookie攻击漏洞就会发生。