一、为什么会跨域
跨域是基于浏览器的同源策略才有的行为。
同源策略是指在浏览器中限制不同源的url互相访问cookiestorage,dom以及发起ajax请求。
同源指的是两个url的协议,域名,端口号都相同。
虽然要谢谢浏览器的好意,但实际开发中常常会碰到不同域之间需要通信的场景,因此从人为创造和w3c标准中都衍生出不少的跨域方式。
二、跨域方法
从前到今,我知道的跨域方法有:
1.document.domain,仅限于共享cookie和dom。适用于两个网页一级域名相同只是二级域名不同的情况。通过在两个网页中分别设置相同的document.domain(一级域名)可以访问到公共的cookie。
2.window.postMessage(),实现父子iframe之间的跨域通信,但是只能传输字符串。
3.jsonp,解决ajax跨域,但只适用于GET请求。
因为浏览器请求静态资源时不受同源策略的限制,因此将http请求封装成静态资源的请求。做法是在网页中动态插入一个
4.Nginx反向代理,解决ajax跨域。
5.Cors通信,解决ajax跨域。详细:www.ruanyifeng.com/blog/2016/0…
Cors是w3c标准,主要是浏览器和服务器的配合,浏览器IE10以上基本支持。整个cors通信过程,都是浏览器自动完成,前端侧无需做什么处理。浏览器一旦发现ajax请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求。而服务器端则需要对cors请求做一些处理。
浏览器将cors请求分为简单请求和非简单请求。
简单请求要求满足两个条件:
1)是get,head,post三种方法之一。
2)http的请求头信息不包括
- Access
- Access-Language
- Content-Language
- Last-Event-ID
- Content-type只限于application/www-form-urlencoded,multipart/form-data,text/plain.
针对简单请求,浏览器会在请求头中添加一个Origin字段,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。
1)如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
2)如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段:
- Access-Control-Allow-Origin: api.bob.com //允许跨域访问的域
- Access-Control-Allow-Credentials: true //是否允许携带cookie,设为true代表允许,但需要前端在请求头中设置withCredentials为true才能生效
- Access-Control-Expose-Headers: FooBar //可选
- Content-Type: text/html; charset=utf-8
对于非简单请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。在预检请求头信息里面,有以下三个关键字段:
Origin:表示请求来自哪个源- **Access-Control-Request-Method:**必须,列出请求会用到哪些HTTP方法
- **ccess-Control-Request-Headers:**该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段
服务器收到"预检"请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。
如果服务器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。
一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。