这些年咱们处理过的跨域

同源策略

在说跨域以前,咱们须要先了解下 同源策略。它是一个规范(Netscape 1995年提出),并无指定具体的使用范围和实现方式。html

为了保证使用者信息的安全,防止恶意网站篡改用户数据,一些常见的Web技术都默认采用了同源策略(如Silverlight, Flash, XMLHttpRequest, Dom等)。前端

那如何判断同源呢?git

  1. 相同的协议
  2. 相同的域名
  3. 相同的的端口号

咱们用一个表格来展现同源的判断:github

URL1 URL2 是否同源 分析
http://www.a.com https://www.a.com 不一样源 协议不一致
http://www.a.com http://www.b.com 不一样源 域名不一致
http://www.a.com http://www.a.com:8080 不一样源 端口不一致
http://www.a.com http://test.a.com 不一样源 域名不一致
http://www.a.com http://www.a.com/test 同源 判断同源和path无关
http://www.a.com http://www.a.com:80 同源 不带端口访问时,默认是80

若是不是同源会有哪些使用限制呢?ajax

  1. Cookie,WebStorage(LocalStorage, SessionStorage),Cache(Application Cache, CacheStorage),Web DB(WebSql IndexDB)等都没法共享json

  2. 没法彼此操做各自的DOM(Iframe)后端

  3. 没法发送Ajax请求api

  4. 其余跨域

注意:若是两个站点,具备相同的一级域名(如 www.a.com, test.a.com,一级域名都是a.com),那么能够经过各自设置document.domain='a.com' 来共享Cookie。浏览器

注意2:若是是iframe非同源,虽然不能操做dom,可是能操做location.href。

什么是跨域?

经过以上内容,咱们了解到了什么是同源策略,以及怎么判断同源。那么与之相反,若是不知足同源,则就是跨域。

在浏览器上,若是访问跨域资源,将会有诸多限制(为了安全),参考上面的同源限制。

注意:跨域限制是浏览器的机制,若是直接在服务端请求,是不会触发跨域限制的。

那些咱们遇到的跨域

一、图片跨域

对于图片来讲,大部分场景是不须要处理跨域限制的,由于通常来讲,图片没有跨域限制。

在也有例外,若是在 Canvas 中操做跨域的图片,那么就会触发跨域限制。解决办法是在返回图片的时候,添加 Access-Control-Allow-Origin: orign | '*' 来容许跨域。

二、Iframe跨域

这个也不太常见,若是网站自己和iframe嵌入的站点都是咱们本身能够控制的,那么应直接使用 postMessage 来通讯。若是浏览器较旧,不支持 postMessage ,能够考虑经过window.name来传递数据。

window.name 传递数据原理

首先在iframe访问跨域的站点,这个站点,将数据写入到window.name中。

而后主站点,修改iframe的location.href='about:blank' 或其余不跨域的站点。

最后经过window.name获取数据

这是由于同一个iframe的window.name是相互共享的。在现代浏览器中,该方式可能会失效,此时请使用 postMessage。

三、字体跨域

跨域使用字体文件,也会触发拦截。这个的解决办法和图片跨域一致,后端设置CORS头部便可。

四、Ajax跨域

这是咱们常常会遇到的跨域问题,因为如今流行的开发模式,不少时候咱们都须要处理这类型的跨域。

如何判断Ajax跨域

当咱们在访问一个Ajax请求,控制台出现以下错误时,咱们基本能够判断,是被跨域拦截了:

XMLHttpRequest cannot load xxxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource.

不少时候,咱们的API和Web并不在一个站点上(多个域名),而咱们又必需要跨域访问。这个时候咱们就须要想办法实现跨域资源访问

如下,咱们就来看看如何实现跨域资源访问:

CORS(跨域资源访问)- 标准作法,强烈推荐

开发模式的演进,致使咱们不少的应用都是跨域访问。这个时候CORS规范也就应运而生了。使用它,咱们能够直接对跨域资源进行访问,了解更多,请参考CORS详解

该方式的核心是经过和后端API协商,看是否容许跨域访问。对于知足某些条件的请求,会先发送一个预请求。简单请求,也须要服务器容许跨域访问。

最关键的的几个响应头以下:

  1. Access-Control-Allow-Origin: origin | '*' 容许某个指定的域访问,*表示不限制域。
  2. Access-Control-Allow-Methods: 'GET,POST,PUT,DELETE' 容许哪些类型的请求
  3. Access-Control-Allow-Headers: 'x-token' 容许的自定义Header。

注意:该方式由服务端设置,前端无需设置,也没法设置。只要服务端处理好了,前端不须要作任何处理便可使用。

反向代理(将跨域代理为同域,绕过)

既然跨域有限制,那么咱们能够考虑将跨域变成同域,这样不就没有限制了么?

Nginx 为例,咱们只须要将特定路径的请求转发给真正的后端API便可:

server {
    listen 8101;
    root /dist;
    index index.html;

    location ~* \.(eot|ttf|woff|woff2)$ {
        add_header x-server $server_addr;
        add_header Access-Control-Allow-Origin '*';
    }
    
    location ^~ /api/v1 {
        proxy_pass http://apis.xxx.com/api/v1;
    }
}

注意:该方式须要在部署的时候作处理,前端须要修改请求api的地址为同域。

服务端转发(经过不跨域的请求跨域API,绕过)

该方式,经过请求不跨域的api,而后在api中再呼叫真实的跨域api,因为是服务端请求,因此也就避开了跨域问题。总体看来,这种方式有点画蛇添足,不过若是把这个转发由统一的程序进行处理,仍是挺不错的。

注意:该方式在后端API中处理,前端须要修改请求api地址为同域。

JSONP(利用script无跨域限制,绕过)

该方式利用Script请求资源不会触发跨域限制这个特色来实现。JSON原理,请参考JSONP详解

注意:该方式须要先后端搭配,后端须要支持JSONP请求,前端须要采用JSONP的方式去请求数据。

注意2:该方式因为实现原理限制,只能处理GET请求。


综上,遇到跨域请求,就先去找后端啊。前端真的独自搞不定啊。

总结

跨域是项目开发中,很是常见的问题。就算是前端开发,也必定要理解跨域,了解跨域的处理方案。以便于可以真正的处理好开发任务(或许,这样和后端交(Si)流(Bi)也更有底气)。

相关文章
相关标签/搜索