`
hereson
  • 浏览: 1453924 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

关于document.domain的一些解释

阅读更多
【全文】
前些天在对公司原有的 web 应用进行改版时遇到一个问题,当时需要从原有的应用中提取出一部分,用一个更为通用的来进行替换,并且仍然保留原有的应用接口。原有的应用属于 news.mycompany.com 域,而新应用将被部署到upload.mycopany.com。当我试着从新的域向 news.mycompany.com 传递数据时,在前台遇到了浏览器返回的“拒绝访问(Access Denied)” 的错误信息,通过参考在google 中查到的大量英文资料找到了问题的症结,并通过指定两个域中页面的docment.domain 属性使问题得到了部分解决。后来一时兴起在 google 中查找与document.domain 相关的中文资料,但得到的大部分是网络安全方面的文章,很少有文章提及通过指定页面的 document.domain 属性能够实现两个域之间的数据交换,于是决定写下此文,希望能够做到抛砖引玉吧。

关键字: JavaScript, Domain, Access Denied
问题的提出
在开发 Web 应用时经常会遇到需要在两个帧之间传递数据的情况,这里的帧可以是 frameset 中的 frame 也可以是独立的窗口。常见的情况是一个帧作为应用的主体,另一个帧则提供一些供用户选择的选项,用户选择完毕后,该帧把用户作出的选择发送到服务器并向主 要的帧传递一些信息,这里的信息可能是用户的选择也可能是服务器返回的数据。当两个帧中的内容同属于一个域时实现以来比较简单,但是当它们分属于不同域时 问题就变得复杂而棘手了,因为这里涉及到了数据访问的安全性问题,搞不好就会遇到浏览器返回的“拒绝访问(Access Denied)” 的错误信息。
可能的解决方案
下面我们将通过几个试验来分析一下在分属于不同域的帧之间传递数据的一些方法。


利用客户端脚本(如 JavaScript)和窗口句柄在两个帧之间传递数据
利用 MSIE 提供的对话框在两个帧之间传递数据
利用服务器端的应用,通过 session 来传递数据

方案一
用客户端脚本实现两个帧之间的数据交换应该是最为轻量级的方式之一了,这样做不会增加服务器的负载也不会占用网络带宽,数据交换完全是在客户端完成。下面就让我们先来了解一下用客户端脚本(以 JavaScript 为例)和窗口句柄如何实现一个域内的数据交换。

我们通过一个实例来进行说明:假设需要给用户提供一个新闻的录入界面,用户可以用它录入新闻的原始内容,并且可以在其中嵌入一副图片。为了实现这个功能界面我们设计了两个帧,或者说是两个窗口:


主窗口: 新闻内容的主要编辑界面,用户可以在里面录入新闻的标题、作者、新闻主体等内容,还有一个图片框可以预览上传的图片
弹出窗口: 处理图片上传的界面,用户可以选择本地图片进行上传,成功后它把服务器上文件的 url 返回给主窗口进行预览

为了简单起见,我们假设两个窗口中的内容都是静态的,主窗口对应的文件为NewsEdit.html,弹出窗口对应的文件为 ImgUpload.html(而大多数情况下两个窗口的内容都应该是动态生成的)。

其中 NewsEdit.html 位于 news.mycompany.com 的主目录下,其源代码如下所示: <!-- File: NewsEdit.html (http://news.mycompany.com/NewsEdit.html) -->
<html>
<head>
<title>The Content Editing Interface</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<script language="JavaScript">
<!--
/* OpenWin 用来在一个弹出窗口中显示 ImgUpload.html 的内容*/
function OpenWin(){//Open window
url='http://news.mycompany.com/upload/ImgUpload.html';
newwindow = window.open(url,"ImgUpload","height=135,width=300");
if (!newwindow.opener) newwindow.opener=self;
}
-->
</script>
</head>

<body>
<h2>Edit your content here</h2>
<!-- 调用后台应用 newsedit 来保存新闻内容 -->
<form action="http://news.mycompany.com/newsedit" method="post"
name="addnews">
<!-- 新闻标题 -->
Title:<input type="text" name="title"><br>
<!-- 新闻作者 -->
Author:<input type="text" name="author"><br>
The content <br>
<!-- 新闻内容 -->
<textarea name="contentBody" cols="100" rows="10"></textarea>
<br>
<!-- 点击连接打开上传图片的小窗口 -->
<a href="JavaScript:OpenWin()">Upload Image File</a>
<br>
<!-- UserImg 用来预览上传成功后的图片文件 -->
<img name="UserImg" style="width: 100px; height: 100px;" src="" border="1">
<br><br>
<input type="submit" name="SaveContent" value="Submit">
<input type="reset" name="ClearContent" value="Reset">
</form>
</html>
ImgUpload.html 位于 news.mycompany.com 的 upload 子目录下,其源代码如下所示: <!-- File: ImgUpload.html
(http://news.mycompany.com/upload/ImgUpload.html) -->
<html>
<head>
<title>Imgage Upload Interface</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>

<body>
<h2>Image Upload</h2>
<!-- 调用后台应用来处理上传的图片 -->
<form action="http://news.mycompany.com/upload/imgupload" method="post"
enctype="multipart/form-data" name="upload">
<!-- 由用户选择本地文件 -->
<input type="file" name="imgfile">
<input type="submit" name="Submit" value="Upload">
</form>
</html>


newsedit: 位于 news.mycompany.com 的主目录下,接受用户的 POST 请求,将编辑界面的新闻元素存储到后台数据库
imgupload: 位于 news.mycompany.com 的 upload 子目录下,接受用户的 POST请求,将本地的图片文件上传到服务器,并返回图片文件完整的 url。
下面是 imgupload 处理完 POST 请求后返回的页面内容,该内容显示在ImgUpload.html 所占据的弹出窗口中: <html>
<head>
<title>File Upload Successfully</title>
</head>
<body>
<h3>File Uploaded Successfully!</h3>
<script language="JavaScript">
<!-- 获取主窗口的句柄 -->
parwin=self.opener;
<!-- 获取对 img 元素的引用,并用上传文件的 url 为 img 元素的 src 属性赋
值,这样在客户端就可以预览了 -->
<!-- 为了简化问题,我们将对 img 元素的引用直接写在程序中 -->
parwin.addnews.UserImg.src="http://news.mycompany.com/img/2003_07/06/1057478464859.gif";
</script>
</body>
</html>


好了,我们的第一个实验已经成功了,实验结果告诉我们:当两个帧中的内容同属于一个域时,利用客户端脚本和窗口句柄在其中传递数据是没有问题的。接下来我 们把 ImgUpload.html 和 imgupload 从 news.mycompany.com 提取出来,部署到img.mycompany.com 的对应目录下,并修改 NewsEdit.html 中引用ImgUpload.html 时的 url。这样当我们试着用 JavaScript 从img.yourcompanu.com 向bbs.yourcompany.com 传递数据时,浏览器就会弹出“拒绝访问(Access Denied)” 的错误框,表明我们违反了他的安全策略,并且数据无法正常传递过来。

我们之所以会遇到“拒绝访问(Access Denied)” 的的错误信息,其原因在于:

“那为什么即使我的两个页面属于同一个域我还是会遇到‘拒绝访问’的错误呀?”如果是这种情况,那就要看你的弹出窗口中的内容是否始终属于同一个域,看一 下你的 ImgUpload.html 是不是调用了属于其他域的应用,并且该应用在窗口中重新写入了内容,如果是这样那你的弹出窗口就变质了,它最后属于另外一个域,你当然会遇到“拒绝访问” 的错误。

是的,一些浏览器的开发商、开发团体在开发高版本的浏览器时对原有策略进行了部分调整,这些调整给我们带来了一线生机:当两个页面在进行数据交换时,浏览 器会首先比较两个页面的 domain 属性,如果domain 属性相同,那么浏览器就允许它们之间的数据交换,否则就返回“拒绝访问(Access Denied)”的错误。



加入上面的声明就可以蒙蔽浏览器,在原本属于两个不同域的页面之间进行数据交换了。但需要注意:只有把上面的声明加入到需要进行数据交换的所有文件中才会 有效,只在一个域的文件中加入上面的声明是不起作用的。另外,声明部分最好能插入到页面的 <head></head> 标记中间,这一点也是用脚本进行开发时所被提倡的。有关 JavaScript 中的 document 和 domain 等可以参考http://www.werelight.com/docs/JavaScript_Quick_Reference.htm
“使用这种方法有什么限制码?”因该说用这种方法来实现不同域之间的数据传递还是有很多的限制的,主要表现为以下两点:


方案二下面我们来看一下利用 MSIE 提供的对话框能不能解决两个域之间的数据交换问题首先我来简单介绍一下 MSIE 对话框:MSIE 提供的 showModalDialog 和showModelessDialog 方法可以用来在一个单独的帧中显示一个模态或非模态对话框,两个方法都通过一个 URI 参数来指定对话框帧中的内容;可选的参数vArguments 用来向对话框帧传递任何类型(包括数组类型)的参数;另外还有一个可选的参数 sFeatures 是用来定义对话框帧的显示效果,如位置、字体等等的;注意 Netscape Navigator 、Mozilla 和 Opera 浏览器是没有与之对应的方法的,也就是说除了 MSIE 之外其他几大浏览器都不支持用 showModalDialog 或showModelessDialog 显示对话框,如果你感兴趣的话这里有一篇文章能够教你如何通过其他方式来模拟一个模态对话框,详见 Simulating Modal Dialog Windows



“那么我能不能像方案一中那样通过强制指定两个页面中的 document.domain 属性来蒙蔽浏览器,使其认为两个页面属于同一个域呢?”确实有人提出过这种想法,笔者也试着这样做过,但最后还以失败而告终:在两个页面中强制指定 document.domain 了属性后,无论两个页面是否属于同一个域,对话框都无法正常识别从主页面传递过来的参数。


main.html : 部署在 a.mycompany.com,通过调用 showModalDialog 引用另外两个文件
localdialog.html : 与 main.html 一起部署在 a.mycompany.com
remotedialog.html : 部署在 b.mycompany.com,其内容与 localdialog.html完全一样
main.html 在调用用 showModalDialog 方法时,通过 vArguments 向对话框传递了参数:"Can you hear me?",希望对话框能够接收到这个参数;如果对话框接收到了,那么它将调用 window.alert() 方法打印出这条消息,然后向main.html 返回一个结果:"Yes I do, I hear you from " + document.domain ;如果main.html 接收到了对话框返回的结果,那么它同样会调用 window.alert() 打印出结果的内容。


localdialog.html(remotedialog.html) 的源代码如下所示: <html>
<head>
<title>a remote dialog</title>
<script>
<!--
//document.domain = "mycompany.com";

onload = function() {
var args = window.dialogArguments;
alert("You send me: " + args.content);
btnCan.onclick = function() {
window.returnValue = "Yes I do, I hear you from " + document.domain;
close();
}
}
-->
</script>
</head>

<body>
Im here, Im a dialog <br>
I will return something to the main window<br>
<input id="btnCan" type="button" style="text-align:center;" value="Close">
</body>
</html>


main.html 总是能正常的接收从对话框中返回的结果,无论对话框是位于a.mycompany.com 还是 b.mycompany.com,也无论是否设置了 document.domain 属性;
在 没有设置 document.domain 属性时,localdialog.html 可以正常接收从main.html 传递过来的参数,但如果设置了 document.domain 属性,localdialog.html 读取到的参数就变成 null 了。
而无论是否设置了 document.domain 属性,在 remotedialog.html 读取从main.html 传递过来的参数得到的始终都是 null。
非常遗憾,实验结果告诉我们:用对话框是无法实现这种跨域的数据交换的。

注(2004 -12-28):您在进行测试的时候可能会得到不同的测试结果,因为随着IE的更新或者补丁的作用,这种跨域的数据交换行为可能会被调整。例如笔者在加入 这段注解的时候上面的第1条就已经不再成立了——main.html 并不是总能接收到从隶属于b.mycompany.com 的对话框返回的数据,只有两者都把document.domain 属性设置为mycompany.com 后main.html 才能接收到对话框返回的结果。见相关讨论:about showModalDialog"Even though there is no mention in the documentation of passing arguments or returning a value being blocked in the cross-domain case, I think that may actually have changed as the consequence of one of the *many* IE upgrades and/or security patches."


总结在上面介绍的三种方案中,除方案二尚不能实现在分属于不同域的帧之间进行数据交换之外,经证明方案一和方案三都是可行的,不过这两种方案又各有利弊:


另外,如果您有其他可选方案的话,非常感谢您能通过 Email 告知我,以填补我在这面方面的空白,谢谢!


参考资料
What does the IE "Access is Denied" error mean?
http://www.dannyg.com/ref/jsminifaq.html#q15 PROPERTY: Document::domain
http://www.powermct.co.kr/teched/ecma/doc_domain.html Writing Cross-Domain Web Applications
http://www.knownow.com/support/devguide/Tutorials/Cross_Domain.html
Why do I get "access denied"-error in IE when calling a function in another frame?
http://www.faqts.com/knowledge_base/view.phtml/aid/1524/fid/127 about showModalDialog
http://www.codecomments.com/IE_Scripting/message180995.html
分享到:
评论

相关推荐

    js设置document.domain实现跨域的注意点分析

    本文实例分析了js设置document.domain实现跨域的注意点。分享给大家供大家参考。具体分析如下: document.domain 用来得到当前网页的域名。 比如在地址栏里输入: 代码如下:[removed]alert&#40;document.domain&#41...

    Web前端黑客技术揭秘(Web2Hack.org)_(i)7.6.5 跨子域:document.domain技巧1

    然而,有时候为了实现特定功能,如单点登录(SSO)或资源共享,开发者会利用`document.domain`属性来打破这种限制,允许跨子域的通信。本节主要探讨的是如何利用`document.domain`技巧进行跨子域操作,并结合一个...

    PHP ajax跨子域的解决方案之document.domain+iframe实例分析

    然而,对于主域相同但子域不同的情况,可以通过设置`document.domain`属性来实现跨子域通信。本文将深入探讨PHP AJAX跨子域的解决方案,特别是使用`document.domain`配合`iframe`的实例分析。 首先,理解`document....

    通过伪协议解决父页面与iframe页面通信的问题

    在某些情况下,开发者可能需要在父页面中设置`document.domain`属性,例如当父页面和子页面(iframe)属于同一顶级域名但二级域名不同时,设置`document.domain`可以使它们视为同源。然而,当父页面显式设置了`...

    javascript中的document.open()方法使用介绍

    在早期的浏览器中,document.open()还有一种用途,即当document.domain被设置为一个新的域名,但又没有得到父域的授权时,会使用document.open()来打开页面的输出,以便继续通信。但现在这种方式不再被推荐使用,...

    基于js中document.cookie全面解析.docx

    此外,还需要注意一些最佳实践,如安全性考虑、大小限制等问题,以确保Cookie的正确使用。 总之,理解`document.cookie`的使用对于Web开发者来说非常重要。通过掌握这些基础知识,可以更好地构建交互式和个性化的...

    跨域解决方案

    document.domain = 'domain.com'; ``` 在子窗口中也需要设置 document.domain: ``` document.domain = 'domain.com'; ``` 这样,我们就可以实现跨域请求。 跨域是前端开发中的一大难题,但我们可以通过各种...

    document 文挡对象详解

    - `document.domain`:返回当前文档的域名,用于跨子域通信。 - `document.lastModified`:显示文档最后修改的时间。 2. **Document对象的常用方法** - `document.createElement()`:创建一个新的HTML元素。 - ...

    Javascript中document.referrer隐藏来源的方法

    实际上,还有其他的技巧和方法可以尝试,比如使用JavaScript设置document.domain属性或者服务器端进行HTTP头信息的控制等。这些技术的实现和应用需要结合具体的业务场景和技术需求进行详细的研究。

    showModalDialog open弹出子窗口操作parent、opener父窗口及跨域处理

    3&gt; IE与FireFox对两个弹出窗口在跨域时的解析也有不同:通过window.dialogArguments操作父窗口时,在IE下不需要指定document.domain而在FireFox下则正好相反需要指定才能生效;采用opener方式操作父窗口时都不需要...

    javascript跨域访问的方法.docx

    修改`document.domain`来跨子域 **1. 基于iframe实现跨域** 这种方法适用于两个页面的域具有共同的基础域,例如aa.xx.com和bb.xx.com。它们必须使用相同的协议(如http或https)和端口(如80或443)。在两个页面...

    详解Document.Cookie

    - 默认情况下,Cookie只能被设置在其创建的源域名内访问,可以通过设置`domain`属性来改变这一行为。 - Cookie可以通过`path`属性指定在哪个路径下有效。 综上所述,`Document.cookie`是JavaScript操作Cookie的主要...

    第16讲 DOM编程-Document对象(三).ppt

    2. **`document.domain`**:用于获取或设置当前文档的域名,通常用于跨子域通信。 3. **`document.title`**:获取或设置页面的标题,对应于`&lt;title&gt;`标签的内容。 4. **`document.documentElement`**:返回文档的根...

    JS跨域请求解决方案.docx

    document.domain = "domain.com"; var iframe = document.getElementById('iframe'); iframe.onload = function() { var iframeDoc = iframe.contentDocument || iframe.contentWindow.document; if (iframeDoc...

    javascript document

    除了上述内容,我们还可以讨论`document`对象的其他关键属性和方法,比如`document.title`用于获取或设置页面标题,`document.URL`获取当前页面的完整URL,`document.domain`获取或设置当前文档的域名,以及`...

    前端解决跨域问题的8种方案.docx

    当两个页面的主域相同但子域不同时,可以通过设置`document.domain`来实现跨域访问。例如,在`www.a.com/a.html`页面中,可以通过以下方式设置`document.domain`并与`www.script.a.com/b.html`进行通信: ```...

    JS_Document

    **JS_Document** ...附带的`js.chm`文件可能是一个帮助文档,包含了更详细关于JavaScript DOM操作的信息,包括实例、方法解释和可能的注意事项。对于深入学习JavaScript DOM编程,查阅此类资源是非常有益的。

Global site tag (gtag.js) - Google Analytics