前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >跨域方法汇总

跨域方法汇总

作者头像
四火
发布2022-07-18 13:41:16
5690
发布2022-07-18 13:41:16
举报
文章被收录于专栏:四火的唠叨

做 Web 开发经常需要面对跨域问题,跨域问题的根源是浏览器安全中的同源策略,比如说,对于 http://www.a.com/1.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 本身的交互本身就有安全性限制。

  1. 利用 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 来调用就写成:

代码语言:javascript
复制
$.getJSON("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=football&callback=?",function(data){
    //...
});

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

4. Flash 跨域:

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

代码语言:javascript
复制
<cross-domain-policy>
    <allow-access-from domain="xxx.xxx.com" />
</cross-domain-policy>
  1. img 标签也可以使用,这也是一种非常常见的方法,功能上面弱一点,只能发送一个 get 请求,没有什么回调,Google 的点击计数就是这样确定的。
  2. window.PostMessage,这个算是 HTML5 新加入的为跨域通讯考虑的机制,只有 Firefox 3、Safari 4 和 IE8 及之后的版本支持。使用它向其它窗口发送消息的调用方式如下:
代码语言:javascript
复制
otherWindow.postMessage(message, targetOrigin);

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

代码语言:javascript
复制
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event){
    if (event.origin !== "http://example.org:8080")
        return;
}

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

  1. Access Control

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

代码语言:javascript
复制
header("Access-Control-Allow-Origin: http://www.a.com");

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

  1. window.name

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

  1. 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 事件。

  1. Cross Frame(CF)

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

  1. Cookie+P3P 协议

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

代码语言:javascript
复制
P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档