一、源
同源策略是浏览器都必须遵循的策略,这就限制了js去调用和修改非同域下的数据。试想如果没有这个策略,在另外一个域的js就能轻易修改当前你正在调用的页面。那就天下大乱,毫无安全可言了。遵循同源策略就对非同域的资源调用加上了许多限制。
我们知道css、image、及js本身(指文件本身)是可以跨域引用的。但html文件和js具体的数据调用如ajax是不能跨域了。还有,所谓同源是指两个页面的协议、域名、端口完全相同,否则都算跨域。通常我们会有很多二级域名,这时需要设置document.domain与主域名一致,否则也认为是跨域。
二、典型的资源共享案例
1)、html做为模板,想被各系统共用。(主次域名)
2)、公开的数据接口想被各系统调用。(不同域名)
3)、请求第三方url结果。(不同域名)
这里先列出这三种需求,因为不同的需求,技术选型也不一样。
三、Cross-Origin
Resource Sharing
这是W3C推出的跨域资源标准规范,其核心部分是通过HTTP请求头来控制跨域的安全性,主要有两个头描述,一是Origin:描述当前的资源是可用来跨域请求的;另外一个是Access-Control-Allow-Orgin:用来描述哪些域是可以访问该资源,允许设置多个。
由于IE8之前的版本及其他浏览器稍低些的版本不遵循此规范,从当前来看其应用还不广泛,因此暂不考虑用此方案来解决上述三个案例。如要对Cross-Origin Resource Sharing进官方进一步了解:http://www.w3.org/TR/cors/。
四、跨域请求资源方案
1、配置反向代理
比如你的资源在ip/resource/resource.html下,中间件只配置resource目录给resource.caidao8.com。现在 有www.caidao8.com、practise.caidao8.com都想跨域调用resource.html。可以通过配置中间件,把ip/resource目录同时配置到域resource.caidao8.com、www.caidao8.com下。这样在resource.caidao8.com要调用resource.html时,就直接这样引用http://resource.caidao8.com/resource/resource.html,同样的在www.caidao8.com要调用时这样引用http://www.caidao8.com/resource/resource.html。实际上如果你有其他不同的域,比如www.caidao8.cn,也可以把资源配置一份到www.caidao8.cn域下。就看你拥有几个域并配置它们。
结论:通过中间件配置让共用资源变成多种域名下可访问是解决跨域的一种有效方法。但方案受限于共享的资源完全由自己控制。还有像tomcat、jetty本身一般不做反向代理,如果要在开发环境查看效果和调试,就得给开发环境也安装nginx/apache,这增加了开发环境的复杂性,考虑到整个团队实施问题,在实际中我们团队没有采用这种方案。
2、IFrame解决跨域问题及其不足之处
IFrame解决跨域问题,只限于a、b是主次域名,首先设置document.domain使主次域名统一。我们设定a是parent,b是放在a下的iframe源。首先在b页面加上一段
<script>$(document).attr(“domain”,”caidao8.com”);</script>(本文所有js代码以jquery表示)。在a下编写js代码:
$jq(document).attr("domain","caidao8.com");
//jquery找不到object,会自动创建此对象
$jq("<iframe id='dddiframe'></iframe>").attr("src","http://testresource.caidao8.com/billtemplate/aaa.html").appendTo("body");
//后续事件必须等iframe资源加载完成后才能操作,而不同的浏览器对iframe资源是否加载完成事件不一致
//iframe下使用jquery的bind与javascript原意attachEvent,两者执行顺序不同,使用jquery bind绑定未果,采用js Dom对象来操作
var iframe = $jq("#dddiframe")[0];
if (iframe.attachEvent){ //解决ie不认iframe onload问题
iframe.attachEvent("onload", function(){
alert($jq("#dddiframe").contents().find("#billid").html());
});
} else {
iframe.onload = function(){
//FF及Chrome能正常获取
alert($jq("#dddiframe").contents().find("body").html());
};
}
注意弯路:因为所请求b的资源是静态资源,一般情况下服务端和浏览器客户端会有缓存,特别是Chrome浏览器,我在开发的过程中,为请求的b资源加了一段
<script>$(document).attr(“domain”,”caidao8.com”);</script>,FF和IE在强刷请求入口后(没有直接强刷b的url,而是强刷a的入口),都产生作用,在Chrome下,强刷a入口,iframe里请求的b资源却还是一直是本地的缓存。这个问题困扰了整整一天,搜了很多资料,还以为是Chrome的一个bug(在Chrome官方也有人提出问题,但没有确认是bug),因为一开始我使用的是12.0.742.91 m版本,使用调试器并没有提示任何出错信息,而是直接在调试器里看到iframe下的contentDocument对象为 undefined;升级Chrome到版本17.0.963.79 m后还是有进步,再进入调试器,这回调试器给出了报错信息,提示协议、域及端口要匹配,这才注意到,原来b资源一直还是本地缓存的资源,直接强刷b资源后,终于把Chrome也搞定了。
结论:如果用iframe来实现跨域访问,数据获取被推到了前端JS,而绕过了服务器,节省服务端资源开销。而且数据直接在客户端交互,速度也最快。在我开发的过程中,请求a的入口http://www.caidao8.com:8080/test而上面的b资源地址是http://testresource.caidao8.com/billtemplate/aaa.html,这两者的端口并不一致,但浏览器似乎有放低同源策略port这个约束标准,这样的端口差异是能被放行的。
Iframe跨域的应用场景受限于主次域名,网上有一种说法,就是a、b两个非主次域名的也通过iframe来实现跨域访问,实际上并不好实现。另外要对所有要引用资源跨域HTML资源加上document.domain=”yourdomain.com”,这无疑也是件麻烦的事情。
3、JSONP
JSONP本质上是一种Javascript注入,通过ajax的方式请求并回调注入服务端数据,它要求服务端提供标准的json格式的数据。
这是freemarker定义的一个标准jsonp返回数据模板样例:
${callback!}({"options":[
<#if datadicts?? && datadicts?size > 0>
<#list datadicts as datadict>
{
"value":"${datadict.key}","text":"${datadict.value}"
}
<#if datadict_has_next>,</#if>
</#list>
</#if>
]});
callback参数就是ajax端请求的回调函数,datadicts是服务端定义的数据,这里略去了JAVA部分的代码,你可以写个Servlet或是Action,把callback及要传出数据按json格式输出。这里用freemarker取例是因为其模板内容看起来更加直观,你也可以直接用servlet response输出你的内容。
再贴PHP写的JSONP服务端代码样例:
<?php
// create a new curl resource
function geturlcontent(){
$ch = curl_init();
// set URL and other appropriate options
curl_setopt($ch, CURLOPT_URL, "http://testresource.caidao8.com/billtemplate/ec51de3cd33749aa8401c9b6854ec2d6.html");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);//不直接输出,返回到变量
$content = curl_exec($ch);
curl_close($ch);
//mb_convert_encoding($content,'utf-8');
return json_encode($content);
}
$fun = $_GET["callback"];
$output = $fun."({\"htmlstr\":".geturlcontent()."})";
echo $output;
?>
Jquery调用jsonp样例:
$jq.getJSON("http://localhost/dong/jsonp/getbilltemplate.php?callback=?",function(data){
$jq("#saveid").before(data.htmlstr);
//因为getJSON默认是异步的,因此必须把后续业务代码跑在这里。
});
结论:为了做比较,本人在开发的过程中特意把iframe实现的跨域请求html功能,用jsonp来实现,之所以使用PHP,是因为PHP在Nginx/apache下能直接解析,因为HTML资源本身与业务无关,这样可以省去java中间件及jvm虚拟机层。由于HTML本身内容不符合json格式,因此在输出时,需要json_encode()方法,经测试发现这样的效率远低于iframe跨域会规,也比不上下面要讲的请求代理方式。因此在请求HTML资源时使用jsonp方式是不合适的。那如果数据本身不是html资源,而是普通的数据,jsonp用来跨域传输公开数据倒是一种既简单又实用方案。jsonp可以在任何不同的域之间调用,前提是你要相信服务端的数据是可信赖和非恶意的,对于服务端来说其数据接口必须是公开的。
4、Open API
目前大型的网站基本上开放或部分开放其API,甚至有人直接把开放API说成云概念,从服务端的角度来理解,开放的API可以理解成是JSONP的进一步扩展,加入了认证校验安全方面的业务。当然服务端可能会进一步收集客户端的流量等数据,对客户端的资源访问做进一步控制。通常API的数据格式会支持JSON、Rest、标准XML格式,相对于JSONP的简单处理,开放API在服务端的设计上要复杂一些,客户端调用一般也需要申请并通过认证后才能调用接口,当然可能有一部分接口是完全公开的。从客户端的角度来说,开放api与jsonp的处理就完全不一样了,开放api需要客户端自己写解析器去解析,因为json、rest风格基本上是一致的,因此也可以到网上直接获取高效的解析器。这里不进一步讲述api服务端及客户端详细实现。
结论:如果服务端想开放数据及数据接口,又有较复杂的权限及资源等业务方面的控制,那无疑要选择Open API。但个人认为在公司内部不同的项目之间,采用开放API的方式也更加有利于代码的集中管理及应用优化。
5、请求代理
这里的请求代理很简单,实际上就是模拟Http请求,然后获取到请求结果后,再转成服务输出。一段JAVA代码样例:
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
…//这里省去一些代码
public void getbilltemplate(){
HttpClient httpClient = new HttpClient();
//创建GET方法的实例
GetMethod getMethod = new GetMethod(Configuration.get("webapp.resource.mediaRoot","http://testresource.caidao8.com")+"/billtemplate/ec51de3cd33749aa8401c9b6854ec2d6.html");
//使用系统提供的默认的恢复策略
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
// new DefaultHttpMethodRetryHandler());
try {
// getRequest().setCharacterEncoding("UTF-8");
//执行getMethod
int statusCode = httpClient.executeMethod(getMethod);
if (statusCode != HttpStatus.SC_OK) {
System.err.println("Method failed: "
+ getMethod.getStatusLine());
}
//读取内容
byte[] responseBody = getMethod.getResponseBody();
writeAjax(new String(responseBody,"UTF-8"));
} catch (HttpException e) {
//发生致命的异常,可能是协议不对或者返回的内容有问题
System.out.println("Please check your provided http address!");
e.printStackTrace();
} catch (IOException e) {
//发生网络异常
e.printStackTrace();
} finally {
//释放连接
getMethod.releaseConnection();
}
}
这段代码的作用,就是先请求url:http://testresource.caidao8.com/billtemplate/ec51de3cd33749aa8401c9b6854ec2d6.html,然后再把获取到的内容输出。你可以把这里的url换成任何你想要的url。这样通过这个代理,你就能获取到你想要的其他站点的资源内容。当然这样获取的资源内容大都就是一堆html内容输出,如果你要获取里面的数据,需要进一步解析内容。下面是用ajax请求这个代理输出
$jq.ajax({
url:"/billstudy/getbilltemplate.hx",
datatype:"html",
cache:false,
async:false,
success:function(data){
$jq("#saveid").before(data);
}
});
由于直接使用datatype:”html”,其效率还是可以接受的。
结论:请求代理可以获取站外任何公开资源,如果进一步抽象和优化,这不就是爬虫的原型么!
五、选型
回到第二大点的三种典型案例,我们可以给出选型答案:
典型的资源共享案例
|
选型参考
|
html做为模板,想被各系统共用。(主次域名)
|
Iframe跨域方案
如果不考虑开发阶段的复杂性:选择配置反向代理方案更加直接。
|
公开的数据接口想被各系统调用。(不同域名)
|
如果是一般数据:jsonp
复杂业务控制的数据:open API
如果是html数据:请求代理
|
请求第三方url结果。(不同域名)
|
请求代理
|
把五种解决方案作列表对比:
解决方案
|
场景描述
|
配置反向代理
|
共享资源属于自己内部,可以把资源随意配置到你拥有域名下。限于文件资源。
|
Iframe跨域
|
限于主次域名的文件资源。
|
jsonp
|
完全跨域并完全公开的json格式数据传输。
|
Open API
|
包含较复杂业务控制及约定的数据传输。
|
请求代理
|
完全跨域的url内容抓取代理。
|
分享到:
相关推荐
跨域引用资源技术是Web开发中的一个重要概念,它涉及到浏览器的同源策略和资源的共享。同源策略是由浏览器强制实施的一种安全策略,确保JavaScript只能访问与当前页面同源(即相同协议、相同域名和相同端口)的网页...
本资料包“Tomcat跨域请求资源解决方案.zip”显然是针对这个问题提供了一个具体的解决方案,主要聚焦于如何在Apache Tomcat服务器上配置以允许跨域请求。 Tomcat是Java Servlet容器,广泛用于部署Java Web应用程序...
前端跨域问题解决
### Ajax跨域问题及其解决方案 #### 一、Ajax跨域问题概述 在现代Web开发中,前后端分离架构越来越流行。这种模式下,前端页面与后端服务通常部署在不同的服务器上,甚至可能位于不同的域名下。当浏览器发起对不同...
### CORS跨域资源共享及其解决方案详解 #### 一、CORS跨域资源共享背景 在现代Web应用开发中,前后端分离已成为一种主流趋势。在这种模式下,前端负责展示逻辑,而后端处理业务逻辑与数据交互。然而,由于浏览器...
综上所述,解决JS跨域访问IFrame的问题,需要根据实际需求和环境选择合适的解决方案,结合服务器端的支持和客户端的技术手段,确保跨域通信的安全和高效。在开发过程中,应充分理解同源策略的限制,熟练掌握跨域通信...
JQuery的跨域解决方案主要依赖于JSONP(JSON with Padding)技术。JSONP是一种绕过同源策略的方式,它利用HTML中的`<script>`标签没有同源策略限制的特点。当jQuery使用`dataType: 'jsonp'`时,它实际上是在做以下几...
同源策略与 File 协议导致的跨域问题解决方案 同源策略是出于安全考虑而诞生的约定,规定了只能在本域内进行资源访问。所谓同源是指“协议+域名+端口”三者相同。不同源之间进行资源访问,就需要跨域。特殊地,有三...
本文将深入探讨前端跨域的基本概念、原理及其解决方案,帮助开发者更好地理解和应对跨域问题。 #### 二、跨域基本概念 ##### 2.1 跨域定义 跨域,通常指的是浏览器出于安全考虑,限制从脚本内发起的跨域HTTP请求...
JavaScript跨域是Web开发中一个常见的挑战,由于浏览器的同源策略限制,JavaScript无法直接访问不同源(协议、域名或端口不一致)的资源。本文将深入探讨JS跨域的解决方案,帮助开发者理解并解决这个问题。 首先,...
跨域图片资源权限(CORS enabled image)是指在Web页面中,当使用canvas元素加载并展示其他域(即非当前源)的图片资源时,由于浏览器同源策略的安全限制,如果没有得到该图片源的明确授权,使用该图片资源的canvas...
为了解决这一问题,并确保在跨域场景下可以正确地处理Cookie信息,本文将详细介绍几种常用的跨域访问解决方案及其在处理Cookie方面的应用。 #### 一、跨域访问解决方案概述 跨域访问是指一个域名下的文档或脚本...
**Ajax跨域访问解决方案** 在Web开发中,Ajax(Asynchronous JavaScript and XML)技术被广泛用于实现页面的异步更新,提升用户体验。然而,由于浏览器的同源策略限制,Ajax请求只能向同源(协议、域名和端口相同)...
JavaScript跨域和Ajax跨域是Web开发中常见的问题,尤其在进行前后端分离或API调用时,由于浏览器的同源策略限制,不同域名、协议或端口的资源请求会被阻止,这就是所谓的“跨域”。本文将深入探讨JavaScript和Ajax...
为了提高用户体验并简化管理流程,单点登录(Single Sign-On,简称SSO)成为了一个重要的技术方案。特别是对于采用ASP.NET框架构建的应用而言,实现跨域SSSO不仅可以提升用户访问多个系统的便捷性,还能够有效降低...
工业物联网中基于边缘计算的跨域计算资源分配与任务卸载 在工业物联网中,现场设备的计算能力有限,基于边缘计算的任务卸载可以有效缓解现场设备的计算压力,提供低时延计算服务。因此,研究了工业物联网中基于边缘...
JSONP是一种较早的跨域解决方案,它利用了浏览器允许`<script>`标签跨域加载资源的特性。通过动态创建`<script>`标签,并指定其`src`属性为一个返回JSON数据的函数调用,服务器将数据包裹在函数调用中返回,客户端...
【跨域分布式云数据中心建设方案】随着信息技术的快速发展,数据中心已成为支撑各类业务和服务的核心基础设施。在"十三五"规划中,大数据和云计算被定位为国家重要发展战略,推动了数据中心的高速增长。然而,传统的...
在IT行业中,尤其是在Web开发领域,跨域问题是一个常见的挑战,尤其当涉及到GIS(地理信息系统)服务时,如Geoserver。Geoserver是一个开源的、基于Java的服务器,用于发布和管理地理空间数据。当从一个源(如浏览器...