前端跨域问题解题大全

开篇

跨域?,作为一个前端开发过程中老生常谈的问题,这是我们既熟悉又陌生的点,既知道简单的处理,又在深层次的问题陷入困惑。 本篇文章将罗列出我们在跨域过程中遇到的常见问题,以及如何解决的办法,疏通我们对于跨域的一些疑惑。

什么是跨域?

跨域是一种HTTP机制,他允许服务端指示来自其他域名的请求是否有权限访问其资源。 跨域同样也依赖于浏览器的preflight机制,用来检查服务端是否允许跨域。

怎样会造成跨域?

当我们从一个域名访问另外一个域名时,例如从a.qq.com -> b.qq.com, 除了我们常见的XMLHttpRequest请求之外,其实还有其他的资源访问方式同样会造成跨域的问题:

  1. 基于XMLHttpRequest或 Fetch API的HTTP请求

  2. Web Fonts字体加载

  3. Web GL图形加载

  4. 使用drawImage()的Canvas图片/音视频

常见的跨域处理办法

我们先从简单常见的一些方法开始,讨论如何解决或者避免跨域。

一、Access-Control

首先我们讨论最为常见的一种方式,既然跨域是一种HTTP协议的限制, 那么通过设置HTTP属性来使其支持跨域便是我们通常解决这个问题最为常见的办法。 那么要如何设置HTTP协议才能使其支持跨域呢?,对于HTTP协议而言控制跨域访问的属性通常是这三个。

当客服端跨域请求发送到服务端时,服务端开放Access-Control*响应,便可以开放跨域资源共享,这也是我们目前最为主流的跨域处理。

二、JSONP

什么是JSONP?,正如我们在前面所提到的怎样才会造成跨域,而JSONP正是利用<script/>标签不会受到跨域的限制,从而避免这个问题。 让我们来看下如何通过JSNOP来实现跨域资源的访问:

三、Iframe跨域

与JSNOP相同Iframe同样是通过避免来解决跨域的,使用Iframe解决跨域的方式有几种,这里我们介绍其中一中document.domain + iframe, 当主域名相同而子域名不同时,我们可以通过统一主域名document.domain来实现,例如:

四、Proxy代理

通过Proxy代理来解决跨域也是一种较为常见的方式,与之前的方案或通过HTTP解决跨域、或通过避免跨域来实现稍有不同, Proxy通过服务端接口转发来实现对于跨域问题的问题,因为HTTP同源策略只在浏览器中生效。 这里介绍几种不同Proxy代理方法:

Webpack-DevServer

这是我们在开发环境下常用的接口代理方法,利用webpack-devserver来解决接口跨域的问题。

Nginx反向代理

对于webpack而言,更多的是在开发环境下使用,而如何在生产环境的使用Proxy,Nginx往往是优先的选择。

Node服务代理

除了Nginx之外,对于前端而言,我们更为常见的自然是通过Node服务来做这个转发啦。

在前一章我们讨论了如何去解决跨域的一些方式,而这里,我们将会讨论另一个由跨域带来的衍生问题Cookie。 当我们在解决了基本的跨域问题之后,如何去处理cookie的携带便是一个新的问题,下面让我们来看下几种具体的情况:

情况一:如何在跨域Cors请求中携带Cookie

首先我们看看最简单也是最实用的一种情况如何在跨域请求中携带Cookie

Access-Control-Allow-Credentials属性意味着请求是否进入信任模式, 在这种模式下Cookie、authorization headers、以及TLS client证书都是受信任的。

情况二:跨域CookieAccess-Control-Allow-Origin: *冲突了怎么办?

HTTP属性Access-Control-Allow-Credentials: tryeAccess-Control-Allow-Origin: *是相互冲突的, 这是因为在HTTP信任模式中,需要指定确定的域名作为信任来源,此时如果我们仍需要进入信任模式, 那么我们便需要将Access-Control-Allow-Origin: xxx.com指向具体的域名地址。

情况三:Proxy代理怎么转发Cookie?

当我们使用服务端Proxy代理时,我们应当怎么去处理cookie呢?,首先让我们看下在Nginx下:

同样是之前那个例子,这次我们添加了proxy_cookie_domain属性,来作为Cookie的转发,在Node代理中呢?

跨域报错了怎么办?

最后我们聊一下在跨域过程中可能遇到的错误,以便我们更好的知悉和应对一些意外的错误。

ERROR:CORS request external redirect not allowed

redirect not allowed出现在当发起的跨域请求并没有被服务端争取返回,而是返回了重定向到其他的域名时,例如:

这种错误经常发生在前端发起一个跨域请求,但是服务端返回30x重定向的情况下, 在这种情况下服务端的30x重定向将不会成功,而会报错。

ERROR:Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’

这种情况出现在客户端请求希望携带credentials标签以传输Cookie时,而服务端Access-Control-Allow-Origin: *却返回*通配符。 此时应将Access-Control-Allow-Origin修改为可以允许跨域访问的域名,而非*通配符。 如若不需要Cookie传输认证,亦可将withCredentials设置为false关闭credentials认证。

ERROR:missing token ‘xyz’ in CORS header ‘Access-Control-Allow-Headers’ from CORS preflight

missing token ‘xyz'意味着跨域请求头中包含了不被允许的请求头字段,这种错误常常发生在preflight预请求中, 在预请求头中包含了不被允许携带的请求字段而导致了后续的正式跨域请求错误。 而这种情况下的错误便需要我们对修改请求头字段或修改Access-Control-Allow-Headers允许携带的字段信息。

Last updated