Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

跨域方法汇总

Posted on 02/13/201406/23/2019 by 四火

browsers

做 Web 开发经常需要面对跨域问题,跨域问题的根源是浏览器安全中的同源策略,比如说,对于 http://www.a.com/1.html 来说:

  • http://www.a.com/2.html 是同源的;
  • https://www.a.com/2.html 是不同源的,原因是协议不同;
  • http://www.a.com:8080/2.html 是不同源的,原因是端口不同;
  • http://sub.a.com/2.html 是不同源的,原因是主机不同。

在浏览器中,<script>、<img>、<iframe> 和<link> 这几个标签是可以加载跨域(非同源)的资源的,并且加载的方式其实相当于一次普通的 GET 请求,唯一不同的是,为了安全起见,浏览器不允许这种方式下对加载到的资源的读写操作,而只能使用标签本身应当具备的能力(比如脚本执行、样式应用等等)。

最常见的跨域问题是 Ajax 跨域访问的问题,默认情况下,跨域的 URL 是无法通过 Ajax 访问的。这里我记录我所了解到的跨域的方法:

1. 服务器端代理,这没有什么可说的,缺点在于,默认情况下接收 Ajax 请求的服务端是无法获取到的客户端的 IP 和 UA 的。

2. iframe,使用 iframe 其实相当于开了一个新的网页,具体跨域的方法大致是,域 A 打开的母页面嵌套一个指向域 B 的 iframe,然后提交数据,完成之后,B 的服务端可以:

  • 返回一个 302 重定向响应,把结果重新指回 A 域;
  • 在此 iframe 内部再嵌套一个指向 A 域的 iframe。

这两者都最终实现了跨域的调用,这个方法功能上要比下面介绍到的 JSONP 更强,因为跨域完毕之后 DOM 操作和互相之间的 JavaScript 调用都是没有问题的,但是也有一些限制,比如结果要以 URL 参数传递,这就意味着在结果数据量很大的时候需要分割传递,甚是麻烦;还有一个麻烦是 iframe 本身带来的,母页面和 iframe 本身的交互本身就有安全性限制。

3. 利用 script 标签跨域,这个办法也很常见,script 标签是可以加载异域的 JavaScript 并执行的,通过预先设定好的 callback 函数来实现和母页面的交互。它有一个大名,叫做 JSONP 跨域,JSONP 是 JSON with Padding 的略称。它是一个非官方的协议,明明是加载 script,为啥和 JSON 扯上关系呢?原来就是这个 callback 函数,对它的使用有一个典型的方式,就是通过 JSON 来传参,即将 JSON 数据填充进回调函数,这就是 JSONP 的 JSON+Padding 的含义。

在互联网上有很多 JSONP 的服务来提供数据,本质上就是跨域请求,并且在请求 URL 中指定好 callback,比如 callback=result,那么在获取到这些数据以后,就会自动调用 result 函数,并且把这些数据以 JSON 的形式传进去,例如(搜索“football”):

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=football&callback=result

使用 JQuery 来调用就写成:

1
2
3
$.getJSON("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=football&callback=?",function(data){
    //...
});

总的来说,JSONP 的跨域方式的局限性在于,只能使用 GET 请求,并且不能解决不同域的两个页面之间如何进行 JavaScript 调用的问题。

4. Flash 跨域:

它会访问目标网站根目录下面的 crossdomain.xml 文件,根据文件中的内容来确定是否允许此次跨域访问:

1
2
3
<cross-domain-policy>
    <allow-access-from domain="xxx.xxx.com" />
</cross-domain-policy>

5. img 标签也可以使用,这也是一种非常常见的方法,功能上面弱一点,只能发送一个 get 请求,没有什么回调,Google 的点击计数就是这样确定的。

6. window.PostMessage,这个算是 HTML5 新加入的为跨域通讯考虑的机制,只有 Firefox 3、Safari 4 和 IE8 及之后的版本支持。使用它向其它窗口发送消息的调用方式如下:

1
otherWindow.postMessage(message, targetOrigin);

在接收的窗口,需要设置一个事件处理函数来接收发过来的消息:

1
2
3
4
5
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event){
    if (event.origin !== "http://example.org:8080")
        return;
}

注意这里必需要使用消息的 origin 和 source 属性来验证发送者的身份,否则会造成 XSS 漏洞。

7. Access Control

有一些浏览器支持 Access-Control-Allow-Origin 这样的响应头,比如:

1
header("Access-Control-Allow-Origin: http://www.a.com");

就指定了允许对 www.a.com 跨域访问。

8. window.name

这个东西其实以前被用作黑客 XSS 的手段,其本质是,当 window 的 location 变化的时候,页面会重新加载,但是有趣的是,这个 window.name 居然不发生变化,那么就可以用它来传值了。配合 iframe,改变几次 iframe 的 window 对象,就完成了实用的跨域数据传递。

9. document.domain

这个方式适用于 a.example.com 和 b.example.com 这种跨域的通信,因为二者有一个共有的域,叫做 example.com,只要设置 document.domain 为 example.com 就可以了,但是如果 a.example1.com 和 b.example2.com 之间要通信,它就没办法了。

10. Fragment Identitier Messaging(FIM)

这个方法很有意思,也需要 iframe 的配合。Fragment Identitier 就是 URL 的井号(#)后面的经常用于锚点定位的部分,这部分的改变不会导致页面刷新,母窗口可以随便访问 iframe 的 URL,而 iframe 也可以随便访问母窗口的 URL,那这二者之间就可以通过改变 Fragmement Identitier 来实现通信了。缺点是 Fragmement Identitier 的改变会产生不必要的历史记录,而且也有长度限制;另外,有的浏览器不支持 onhashchange 事件。

11. Cross Frame(CF)

这种方法是上述 FIM 方法的变种,CF 和 FIM 的本质其实在我的 《GWT 初体验》这篇文章里面都有介绍(只不过是被用来实现历史和后退功能了),它会动态创建一个不可见的 iframe,指向异域,处理完以后,这个 iframe 的 URL 中的 Fragment Identitier 包含了处理结果,供母页面访问,而浏览器的 URL 没有任何变化。

12. Cookie+P3P 协议

利用 P3P 协议下跨域访问 Cookie 的特性,来实现跨域访问,也算一奇招。P3P 是 W3C 公布的一项隐私保护推荐标准,旨在为网上冲浪的 Internet 用户提供隐私保护。把 Cookie 的 path 设置为“/”,即没有任何域的限制,这个时候有的浏览器下面允许别的 URL 的页面来读取,有的则不允许,这种情况下需要在母页面响应的头上面设置 P3P 的头:

1
P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. HTTP 劫持
  2. JavaScript 并发下载
  3. 前端解耦的一个最简单示例
  4. 网络图形标准
  5. 从 JavaScript 的单线程执行说起

1 thought on “跨域方法汇总”

  1. seoer says:
    08/04/2015 at 4:42 PM

    总结的很全面~~

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Python Spark 互联网 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 程序员 管理 系统设计 缓存 编码 编程范型 英语 西雅图 设计 评审 问题 面试 项目

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Big Data and Machine Learning (5)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • + 1.943624 BTC.NEXT - https://graph.org/Ticket--58146-05-02?hs=9a9c6f8dfe3cdbe0074006e3e640b19b& on 所有文章
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
  • Anonymous on 我裸辞了
  • Dylan on 我裸辞了
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme
Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接