Cross-window Communication
JavaScript Cross-window Communication (JavaScript跨窗口通信)
The Same Origin policy restricts the windows access to one another. That means, if a user has opened two pages: the first one from daivd-brown.com and the second one - gmail.com, then they couldn’t want a script from daivd-brown.com for reading a mail from gmail.com. The purpose of such a policy is to protect users from information theft.
Describing the Same Origin
Describing the Same Origin (描述同源)
Two URLs are considered to have the same origin when their protocol, domain, and port are the same. (当两个URL的协议、域和端口相同时,它们被认为具有相同的来源。)
Here are examples of same-origin URLs:
http://oursite.com
http://oursite.com/
http://oursite.com/my/page.html
Now, let’s see examples of URLs that don’t have the same origin:
http://site.org
http://www.site.com
https://site.com
http://site.com:8080
According to the Same Origin policy:
In case of having a reference to another window ( for example, a popup created with or a window inside <iframe>, and the window is from the same origin, then complete access to that window is provided.
In another way, in case of coming from another origin, then the content of the window can’t be accessed. Only the location can be an exception: it can be modified. But, the location can’t be read.
iFrame
<iframe>
window (窗口)
document (文件)
iframe.contentWindow for accessing the window within the <iframe>.
iframe.contentDocument for getting the document within <iframe>. It’s a shorthand for iframe.contentWindow.document.
While accessing something inside the embedded window, the browser inspects whether the iframe has the same origin. Otherwise, access will be denied. In the example below, you can see an attempt to read and write to <iframe> from another origin:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe id="iframe" src="https://example.com"></iframe>
<script>
iframe.onload = function() {
// get the reference to the inner window
(//获取对内部窗口的引用)
let iframeWindow = iframe.contentWindow; // OK
try {
//but not to the document inside it
(//但不适用于其中的文档)
let doc = iframe.contentDocument; // ERROR
} catch(err) {
alert(err); // Security Error, another origin
}
// also we cannot READ the page URL in the iframe
(//此外,我们无法读取iframe中的页面URL)
try {
// Cannot read URL from Location object
(//无法从Location对象读取URL)
let href = iframe.contentWindow.location.href; // ERROR
} catch(err) {
alert(err); // Security Error
}
//can be WRITE to a location (and therefore load something else in the iframe)
(//可以写入位置(因此在iframe中加载其他内容))
iframe.contentWindow.location = '/'; // OK
iframe.onload = null; // clear the handler so that it does not start after changing the location
};
</script>
</body>
</html>
But this code will lead to errors in all circumstances except:
Receiving the reference to the inner window iframe.contentWindow . (-接收对内部窗口iframe.contentWindow的引用。)
While writing to the location . (-在写信给房源时。)
Differently, when the <iframe> has the same origin, anything can be done with it, like here:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<!-- iframe from the same site -->
<iframe id="iframe" src="/"></iframe>
<script>
iframe.onload = function() {
// just do anything
(//做任何事情)
iframe.contentDocument.body.prepend("Welcome to w3cdoc");
};
</script>
</body>
</html>
Windows on Subdomains: document.domain
Windows on Subdomains: document.domain
So, by default two URLs that have different domains have different origins. But, when windows have the same second-level domain, it is possible to make the browser ignore the difference. (因此,默认情况下,具有不同域的两个URL具有不同的来源。 但是,当窗口具有相同的二级域时,可以使浏览器忽略差异。)
The following code should be run to make it work:
document.domain = 'oursite.com';
Iframe: wrong document pitfall
Iframe: wrong document pitfall
If the iframe is from the same origin with a possibility of accessing its document, then there exists a pitfall. It is an essential thing to know but doesn’t relate to cross-origin requests. (如果iframe来自同一来源,并且有可能访问其文档,则存在陷阱。了解这一点至关重要,但与跨源请求无关。)
So, doing something with the document at once will be lost:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe id="iframe" src="/" ></iframe>
<script>
let oldDocs = iframe.contentDocument;
iframe.onload = function() {
let newDocs = iframe.contentDocument;
// the loaded document is different from the original
(//加载的文档与原始文档不同)
alert(oldDocs == newDocs); // false
};
</script>
</body>
</html>
That’s the wrong document. Setting any event handlers on it will be ignored. The right document is where iframe.onload occurs. However, it occurs only when the total iframe with all the resources is loaded. (这是错误的文件。 在其上设置任何事件处理程序将被忽略。 正确的文档是iframe.onload发生的地方。 但是,只有加载了包含所有资源的总iframe时才会发生这种情况。)
With setInterval the moment can be caught earlier, like here:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe id="iframe" src="/" ></iframe>
<script>
let oldDocs = iframe.contentDocument;
// every 100 ms we check if the document is new
(//每隔100毫秒,我们会检查文档是否是新的)
let timer = setInterval(() => {
let newDocs = iframe.contentDocument;
if (newDocs == oldDocs) return;
alert("New document is here");
clearInterval(timer); // cancel setInterval, no longer needed
}, 500);
</script>
</body>
</html>
Window.frames
Window.frames (窗框)
There is an alternative option of getting a window object for <iframe>.
You can get it from the named collection window.frames :
By number window.frames[0] (按数字window.frames [0]) . By name window.frames.iframeName. (。 按名称window.frames.iframeName。)
Let’s take a look at an example:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe id="iframe" src="/" style="height:100px" name="win"></iframe>
<script>
alert(iframe.contentWindow == frames[0]); // true
alert(iframe.contentWindow == frames.win); // true
</script>
</body>
</html>
Cross-window Messaging
Cross-window Messaging (跨窗口消息传递)
Windows can talk to each other no matter what origin they have, with the help of the postMessage interface. (借助postMessage界面, Windows可以相互通信,无论其来源如何。)
So, with it, a window from david-brown.com can exchange information with gmail.com, but only when they both agree and call the matching JavaScript functions. (因此,通过它,来自david-brown.com的窗口可以与gmail.com交换信息,但前提是它们都同意并调用匹配的JavaScript函数。)
It makes the operation safe for users. (它使用户可以安全地进行操作。)
The interface includes two parts that are postMessage and onmessage. (界面包括postMessage和onmessage两部分。)
PostMessage
The psotMessage method is called when the window intends to send a message. That is, when you need to send a message to win, you need to call win.postMessage(data, targetOrigin). (当窗口打算发送消息时,会调用psotMessage方法。也就是说,当您需要发送消息以获胜时,您需要调用win.postMessage (data, targetOrigin)。)
It includes the following arguments:
data: it includes the data to send. A structured cloning algorithm is used to clone data.
targetOrigin: it indicates the target window origin. So, only a window from a particular origin will receive the message.
Let’s check out an example:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe src="http://example.com" name="example">
<script>
let win = window.frames.example;
win.postMessage("message", "http://example.com");
</script>
</body>
</html>
Also, you can set targetOrigin to * if the check is not necessary for you:
<!DOCTYPE html>
<html>
<head>
<title>Title of the Document</title>
</head>
<body>
<iframe src="http://example.com" name="example">
<script>
let win = window.frames.example;
win.postMessage("message", "*");
</script>
</body>
</html>
Onmessage
The target window must have a handler on the message event to get a message. It occurs once postMessage is called. (目标窗口必须在消息事件上具有处理程序才能获取消息。一旦调用postMessage ,就会发生这种情况。)
The properties of the event object are as follows:
data: the postMessage data.
origin: the sender origin. For instance, https://www.w3cdoc.com/.
source: a reference to the window of the sender.
Here, addEventListener should be applied for assigning the handler. (在这里,应应用addEventListener来分配处理程序。)
The window.onmessage syntax will not operate. (Window.onmessage语法将不工作。)
The example will look like this:
window.addEventListener("message", function (event) {
if (event.origin != 'http://javascript.info') {
// something from an unknown domain, let's ignore it
(//来自未知域的内容,让我们忽略它)
return;
}
alert("received: " + event.data);
// can message back using event.source.postMessage(...)
});
Summary
Summary (概要)
For calling methods and accessing another window content, a reference is necessary. (对于调用方法和访问另一个窗口内容,引用是必需的。)
The following references are used for popups:
window.open for the opener window. (-窗口。打开打开器窗口。)
window.opener from the popup. (-弹出窗口中的window.opener。)
In case the windows have the same origin, they can do anything to one another. Otherwise, it’s only possible to change the location and post a message to it. (如果窗户具有相同的原点,它们可以互相做任何事情。否则,您只能更改位置并向其发布消息。)
The postMessage interface helps two windows with different origins to interact. (PostMessage界面帮助两个不同来源的窗口进行交互。)
The targetWin.postMessage(data, targetOrigin) is called by the sender. If targetOrigin is not ‘’, then the browser checks whether there is targetOrigin in the targetWin window. If it’s there, the message event is triggered by the targetWin . (发送方调用targetWin.postMessage (data, targetOrigin)。 如果targetOrigin不是’’ ,则浏览器会检查targetWin窗口中是否存在targetOrigin。 如果存在,则消息事件由targetWin触发。)