前端跨域解决方案
前端跨域解决方案
目录
1. 同源策略2. 如何解决跨域?
2.1 CORS
2.1.1 CORS定义2.1.2 CORS请求分类2.1.3 简单请求和非简单请求的过程2.1.4 减少OPTIONS请求次数2.1.5 CORS中Cookie相关问题
2.2 jsONP2.3 代理跨域
1. 同源策略
跨域问题其实就是浏览器的同源策略造成的。
同源策略限制了从同一个源加载的文档或脚本如何与另一个源的资源进行交互。这是浏览器的一个用于隔离潜在恶意文件的重要的安全机制。同源指的是:协议、端口号、域名必须一致。
下表给出了与 URL 的源进行对比的示例:
URL | 是否跨域 | 原因 |
完全相同 | ||
只有路径不同 | ||
协议不同 | ||
端口不同 ( 默认端口是80) | ||
主机不同 |
同源策略:protocol(协议)、domain(域名)、port(端口)三者必须一致。
2. 如何解决跨域?
很多情况下,我们前后端资源可能不在一台服务器上,那就需要进行跨域请求。
下面看一下解决跨域的方式有哪些:
2.1 CORS
2.1.1 CORS定义
下面是MDN对于CORS的定义:
跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain)上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域HTTP 请求。
CORS需要浏览器和服务器同时支持,整个CORS过程都是浏览器完成的,无需用户参与。因此实现CORS的关键就是服务器,只要服务器实现了CORS请求,就可以跨源通信了。
2.1.2 CORS请求分类
浏览器将CORS分为简单请求和非简单请求:
简单请求不会触发CORS预检请求。若该请求满足以下两个条件,就可以看作是简单请求:1)请求方法是以下三种方法之一:
HEADGETPOST
2)HTTP的头信息不超出以下几种字段:
AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:只限于三个值application/x-简单请求和非简单请求的过程
(1)简单请求过程:
对于简单请求,浏览器会直接发出CORS请求,它会在请求的头信息中增加一个Orign字段,该字段用来说明本次请求来自哪个源(协议+端口+域名),服务器会根据这个值来决定是否同意这次请求。
如果Orign指定的域名在许可范围之内,服务器返回的响应就会多出以下信息头:
Access-Control-Allow-Origin: // 和Orign一直Access-Control-Allow-Credentials: true // 表示是否允许发送CookieAccess-Control-Expose-Headers: FooBar // 指定返回其他字段的值Content-Type: text/html; charset=utf-8 // 表示文档类型
如果Orign指定的域名不在许可范围之内,服务器会返回一个正常的HTTP回应,浏览器发现没有上面的Access-Control-Allow-Origin头部信息,就知道出错了。这个错误无法通过状态码识别,因为返回的状态码可能是200。
在简单请求中,在服务器内,至少需要设置字段:Access-Control-Allow-Origin
(2)非简单请求过程
非简单请求是对服务器有特殊要求的请求,比如请求方法为DELETE或者PUT等
非简单请求的CORS请求会在正式通信之前进行一次HTTP查询请求,称为预检请求。
浏览器会询问服务器,当前所在的网页是否在服务器允许访问的范围内,以及可以使用哪些HTTP请求方式和头信息字段,只有得到肯定的回复,才会进行正式的HTTP请求,否则就会报错。
预检请求使用的请求方法是OPTIONS,表示这个请求是来询问的。他的头信息中的关键字段是Orign,表示请求来自哪个源。除此之外,头信息中还包括两个字段:
Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。Access-Control-Request-Headers: 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。
服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进行判断,如果返回的头信息在中有Access-Control-Allow-Origin这个字段就是允许跨域请求,如果没有,就是不同意这个预检请求,就会报错。
服务器回应的CORS的字段如下:
Access-Control-Allow-Origin: // 允许跨域的源地址Access-Control-Allow-Methods: GET, POST, PUT // 服务器支持的所有跨域请求的方法Access-Control-Allow-Headers: X-Custom-Header // 服务器支持的所有头信息字段Access-Control-Allow-Credentials: true // 表示是否允许发送CookieAccess-Control-Max-Age: 1728000 // 用来指定本次预检请求的有效期,单位为秒
只要服务器通过了预检请求,在以后每次的CORS请求都会自带一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
在非简单请求中,至少需要设置以下字段:
'Access-Control-Allow-Origin' 'Access-Control-Allow-Methods''Access-Control-Allow-Headers'
2.1.4 减少OPTIONS请求次数
OPTIONS请求次数过多就会损耗页面加载的性能,降低用户体验度。
所以尽量要减少OPTIONS请求次数,可以后端在请求的返回头部添加:Access-Control-Max-Age:number。它表示预检请求的返回结果可以被缓存多久,单位是秒。
该字段只对完全一样的URL的缓存设置生效,所以设置了缓存时间,在这个时间范围内,再次发送请求就不需要进行预检请求了。
2.1.5 CORS中Cookie相关问题
在CORS请求中,如果想要传递Cookie,就要满足以下三个条件:
(1)在请求中设置 withCredentials
默认情况下在跨域请求,浏览器是不带 cookie 的。但是我们可以通过设置 withCredentials 来进行传递 cookie.
// 原生 xml 的设置方式var xhr = new XMLHttpRequest();xhr.withCredentials = true;// axios 设置方式axios.defaults.withCredentials = true;
(2)Access-Control-Allow-Credentials 设置为 true
(3)Access-Control-Allow-Origin 设置为为非 *
2.2 JSONP
JSONP跨域主要是利用