摘要:因为浏览器的同源策略,前端开发会遇到各种跨域问题。前言在总结各种跨域问题之前,我们先来了解一下浏览器的同源策略。所以只能解决一级域名相同二级域名不同的跨域问题。
跨域问题的场景和解决方案多种多样,只要是做前端开发,总会遇到。而且面试时也是必问的问题。所以自己学习总结记录一下。
因为浏览器的同源策略,前端开发会遇到各种跨域问题。本篇文章总结了遇到跨域问题的不同的场景以及对应的解决方案。
前言在总结各种跨域问题之前,我们先来了解一下浏览器的同源策略。
协议、域名、端口都相同才叫同源。具体的这里就不赘述了。
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,"同源政策"是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
受到同源限制:
1)无法读取不同源的 Cookie、LocalStorage 和 IndexDB 。
2)无法获得不同源的DOM 。
3)不能向不同源的服务器发送ajax请求。
不受同源限制:
在浏览器中,、、、等标签都可以跨域加载资源,而不受同源策略的限制。
浏览器对跨域访问的判定:
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
凡是不同时满足上面两个条件,就属于非简单请求。浏览器对这两种请求的处理,是不一样的。
简单请求:浏览器会带上Origin的请求头发送到服务器,服务器根据Origin判断是否许可。如果许可就会带上CORS相关想要头,如果不在许可范围内就不会带上CORS相关的响应头。浏览器再根据响应头中是否有相关的CORS响应头,来判断拦截响应body和抛出错误。
非简单请求:非简单请求会在发真正的请求之前发送一个OPTIONS的带着Origin、Access-Control-Request-Method、Access-Control-Request-Headers等CORS相关的请求头的预检请求到服务器,服务器确认可以这样请求,就会返回带着Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers等CORS相关的响应头的响应,浏览器检查到相关的CORS响应头,说明通过预检可以继续发送真正的请求;服务器确认不可以,则不会返回这些相关响应头,浏览器没检查到CORS的响应头就会抛出错误。
场景1:你的项目myweb,myweb的前端有一个接口是去访问一个非myweb的服务器。非myweb服务器是第三方服务器,你不能去对第三方服务器做改动。
场景2:你的项目是个微服务架构的。那你的前端页面可能就需要去很多个服务器上访问数据。
原理解析:
跨域请求报错归根结底是浏览器禁止使用XHR对象向不同源的服务器地址发起HTTP请求。如果是服务器跨域向多个不同的服务器发送请求就不会有跨域问题存在。因此,我们可以让浏览器只向一个服务器方式请求,让这个服务器代替浏览器去不同的服务器上请求资源再返回给浏览器。这个服务器就是代理服务器了。
下面推荐一个常用代理服务器nginx。
什么是nginx?
Nginx (engine x) 是一款轻量级的Web 服务器 、反向代理服务器及电子邮件(IMAP/POP3)代理服务器。
把ui所在的服务器和跨域服务器都用nginx代理转发,浏览器访问nginx,nginx到ui服务获取ui,再把ui下载到浏览器,浏览器发起ui中的URL,该URL为Nginx封装后的跨域服务器的URL或ui服务器的URL,该URL到达Nginx之后,会被转发到跨域服务器或ui服务器,请求处理完毕后,会通过Nginx中转返回给浏览器。暴露出来的或者浏览器所发起的url都是nginx的url,nginx去跨域服务器和ui服务器获取响应,返给浏览器,这样就没有跨域问题了。
二、CORS场景:
前后端分离的开发模式下,在本地进行接口联调时:也许在你的项目里,你想尝试前后端分离的开发模式。你在本地开发时,mock了一些假数据来帮助自己本地开发。而有一天,你希望在本地和后端同学进行联调。此时,后端rd的接口地址和你发生了跨域问题。这阻止了你们的联调,你只能继续使用你mock的假数据。
解决方案:
CORS需要浏览器和服务器同时支持。如何支持?请看浏览器对跨域访问的判定小节。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
服务器要给接口的响应头设置:Access-Control-Allow-Origin:*
场景:跨域发送get请求
jsonp解决跨域问题的本质: