一, 常见跨域方法
1) JSONP 跨域 需要目标服务器配合一个 callback 函数
2) Ajax 跨域 CORS
3) 使用 Windows.name+iframe 来进行跨域
4) Windows.postMessage: 跨文档通信 API(Cross-document messaging)
5) 跨子域: 修改 document.domain
6) 通过 Nginx 反向代理
7) WebSocket
二, 原理及其用例
JSONP 跨域:
原理:
<script > 可跨域请求资源, JSON 格式被原生 JavaScript 支持, 客户端与服务器端配合
客户端动态定义并实现一个函数, 将函数添加到请求的目标 URL 中, 通过创建 <script src="URL">跨域请求资源
服务器端接受到请求, 获取添加在请求 URL 中的函数, 将需要的数据以参数的形式传入获取到的函数中并返回
客户端获取到带有参数 (需要的数据) 的函数, 执行该函数(客户端已经定义并实现了该函数), 处理数据
用例:
客户端代码:
- <!DOCTYPE HTML>
- <HTML>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <title>
- JSONP
- </title>
- <style>
- body, input, select, button, h1 { font-size: 28px; line-height:1.7; }
- </style>
- </head>
- <body>
- <h1>
- 员工查询
- </h1>
- <label>
- 请输入员工编号:
- </label>
- <input type="text" id="keyword" />
- <button id="search">
- 查询
- </button>
- <p id="searchResult">
- </p>
- <script>
- /**
- * 原理:
- * <script > 可跨域请求资源, JSON 格式被原生 JavaScript 支持, 客户端与服务器端配合
- * 客户端动态定义并实现一个函数, 将函数添加到请求的目标 URL 中, 通过创建 <script src="URL">跨域请求资源
- * 服务器端接受到请求, 获取添加在请求 URL 中的函数, 将需要的数据以参数的形式传入获取到的函数中并返回
- * 客户端获取到带有参数 (需要的数据) 的函数, 执行该函数(客户端已经定义并实现了该函数), 处理数据
- */
- function myJSONP(url) {
- // 创建一个十位数的随机数
- var randomNumber = Math.random().toString().substring(2, 12);
- // 生成 cbname(JSONP 请求用到的回调函数, 后面会添加到 URL 中)
- var cbname = "callbackName" + randomNumber;
- // 将 cbname 函数挂载到 myJSONP 函数上(即 myJSONP 里面有一个 cbname 函数)
- var myJSONP_cbname = "myJSONP." + cbname;
- // 实现 cbname 回调函数
- myJSONP[cbname] = function(response) {
- try {
- // var data=JSON.parse(data); // 返回的数据已经是 JSON 格式, 所以不用转换, 否则错误
- if (response.success) document.querySelector("#searchResult").innerHTML = response.msg; // 请求成功
- else document.querySelector("#searchResult").innerHTML = "出现错误:" + response.msg; // 请求失败
- } finally {
- // 请求完成, 删除函数以及移除脚本
- delete myJSONP[cbname];
- script.parentNode.removeChild(script);
- }
- };
- // 创建 script 用于发送请求
- var script = document.createElement("script");
- // 将 myJSONP 里面的 cbname 函数添加到 URL 中
- if (url.indexOf("?") === -1) {
- url += "?callback=" + myJSONP_cbname;
- } else {
- url += "&callback=" + myJSONP_cbname;
- }
- // 将脚本的 src 指向请求 URL, 然后将脚本添加到页面中, 触发 http 请求
- script.src = url;
- document.body.appendChild(script);
- }
- document.querySelector("#search").onclick = function() {
- // JSONP 跨域请求(模拟跨域请求)
- // JSONP.HTML 在浏览器中打开的地址为: http://localhost/JSONP.HTML
- // JSONP.PHP 服务器地址为: http://127.0.0.1:80/jsonp.php
- var url = "http://127.0.0.1:80/jsonp.php?number=" + document.querySelector("#keyword").value;
- myJSONP(url);
- }
- </script>
- </body>
- </HTML>
服务器端代码:
- <?PHP
- // 设置页面内容是 HTML 编码格式是 utf-8
- // header("Content-Type: text/plain;charset=utf-8");
- header("Content-Type: application/json;charset=utf-8");
- //header("Content-Type: text/xml;charset=utf-8");
- //header("Content-Type: text/html;charset=utf-8");
- //header("Content-Type: application/javascript;charset=utf-8");
- // 定义一个多维数组, 包含员工的信息, 每条员工信息为一个数组
- $staff = array
- (
- array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
- array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
- array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
- );
- // 判断如果是 get 请求, 则进行搜索; 如果是 POST 请求, 则进行新建
- //$_SERVER 是一个超全局变量, 在一个脚本的全部作用域中都可用, 不用使用 global 关键字
- //$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
- if ($_SERVER["REQUEST_METHOD"] == "GET") {
- search();
- } elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
- create();
- }
- // 通过员工编号搜索员工
- function search(){
- $JSONP = $_GET["callback"];
- // 检查是否有员工编号的参数
- //isset 检测变量是否设置; empty 判断值为否为空
- // 超全局变量 $_GET 和 $_POST 用于收集表单数据
- if (!isset($_GET["number"]) || empty($_GET["number"])) {
- echo $JSONP . '({"success":false,"msg":" 参数错误 "})';
- return;
- }
- // 函数之外声明的变量拥有 Global 作用域, 只能在函数以外进行访问.
- //global 关键词用于访问函数内的全局变量
- global $staff;
- // 获取 number 参数
- $number = $_GET["number"];
- $result = $JSONP . '({"success":false,"msg":" 没有找到员工."})';
- // 遍历 $staff 多维数组, 查找 key 值为 number 的员工是否存在, 如果存在, 则修改返回结果
- foreach ($staff as $value) {
- if ($value["number"] == $number) {
- $result = $JSONP . '({"success":true,"msg":" 找到员工: 员工编号:'. $value["number"] .
- ', 员工姓名:' . $value["name"] .
- ', 员工性别:' . $value["sex"] .
- ', 员工职位:' . $value["job"] . '"})';
- break;
- }
- }
- echo $result;
- }
- // 创建员工
- function create(){
- // 判断信息是否填写完全
- if (!isset($_POST["name"]) || empty($_POST["name"])
- || !isset($_POST["number"]) || empty($_POST["number"])
- || !isset($_POST["sex"]) || empty($_POST["sex"])
- || !isset($_POST["job"]) || empty($_POST["job"])) {
- echo '{"success":false,"msg":" 参数错误, 员工信息填写不全 "}';
- return;
- }
- //TODO: 获取 POST 表单数据并保存到数据库
- // 提示保存成功
- echo '{"success":true,"msg":" 员工:'. $_POST["name"] .' 信息保存成功!"}';
- }
- ?>
运行结果:
CORS 请求分成两类: 简单请求 (simple request) 和非简单请求(not-so-simple request)
原理: 详情点击这里 http://www.ruanyifeng.com/blog/2016/04/cors.html (阮一峰的这篇博客讲得很清楚)
http://www.ruanyifeng.com/blog/2016/04/cors.html
用例:
Ajax 跨域之 CORS "跨域资源共享"(Cross-origin resource sharing)GET 请求之简单请求:
客户端代码:
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- Document
- </title>
- <style>
- body, input, select, button, h1 { font-size: 28px; line-height:1.7; }
- </style>
- </head>
- <body>
- <h1>
- 查询员工
- </h1>
- <label>
- 请输入员工编号:
- </label>
- <input type="text" id="keyword" />
- <button id="search">
- 查询
- </button>
- <p id="searchResult">
- </p>
- <script>
- function handlerResponse(response) {
- var response = JSON.parse(response);
- if (response.success) document.querySelector("#searchResult").innerHTML = response.msg; // 请求成功
- else document.querySelector("#searchResult").innerHTML = "出现错误:" + response.msg; // 请求失败
- }
- document.querySelector("#search").onclick = function() {
- // CORS 跨域请求(模拟跨域请求)
- // AjaxCORS.HTML 在浏览器中打开的地址为: http://localhost/AjaxCORS.HTML
- // AjaxCORS.PHP 服务器地址为: http://127.0.0.1:80/AjaxCORS.php
- var url = "http://127.0.0.1:80/AjaxCORS.php?number=" + document.querySelector("#keyword").value;
- ajaxGET(url, handlerResponse);
- }
- function ajaxGET(url, callback) {
- var xhr = new XMLHttpRequest();
- xhr.open("GET", url);
- xhr.send(null);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4 && xhr.status == 200) {
- callback(xhr.responseText);
- }
- }
- }
- </script>
- </body>
- </HTML>
服务器端代码:
- <?PHP
- // 设置页面内容是 HTML 编码格式是 utf-8
- // header("Content-Type: text/plain;charset=utf-8");
- header('Access-Control-Allow-Origin:*');
- header('Access-Control-Allow-Methods:POST,GET');
- header('Access-Control-Allow-Credentials:true');
- header("Content-Type: application/json;charset=utf-8");
- //header("Content-Type: text/xml;charset=utf-8");
- //header("Content-Type: text/html;charset=utf-8");
- //header("Content-Type: application/javascript;charset=utf-8");
- // 定义一个多维数组, 包含员工的信息, 每条员工信息为一个数组
- $staff = array
- (
- array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
- array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
- array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
- );
- // 判断如果是 get 请求, 则进行搜索; 如果是 POST 请求, 则进行新建
- //$_SERVER 是一个超全局变量, 在一个脚本的全部作用域中都可用, 不用使用 global 关键字
- //$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
- if ($_SERVER["REQUEST_METHOD"] == "GET") {
- search();
- } elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
- create();
- }
- // 通过员工编号搜索员工
- function search(){
- // 检查是否有员工编号的参数
- //isset 检测变量是否设置; empty 判断值为否为空
- // 超全局变量 $_GET 和 $_POST 用于收集表单数据
- if (!isset($_GET["number"]) || empty($_GET["number"])) {
- echo '{"success":false,"msg":" 参数错误 "}';
- return;
- }
- // 函数之外声明的变量拥有 Global 作用域, 只能在函数以外进行访问.
- //global 关键词用于访问函数内的全局变量
- global $staff;
- // 获取 number 参数
- $number = $_GET["number"];
- $result = '{"success":false,"msg":" 没有找到员工."}';
- // 遍历 $staff 多维数组, 查找 key 值为 number 的员工是否存在, 如果存在, 则修改返回结果
- foreach ($staff as $value) {
- if ($value["number"] == $number) {
- $result = '{"success":true,"msg":" 找到员工: 员工编号:'. $value["number"] .
- ', 员工姓名:' . $value["name"] .
- ', 员工性别:' . $value["sex"] .
- ', 员工职位:' . $value["job"] . '"}';
- break;
- }
- }
- echo $result;
- }?>
运行结果:
Ajax 跨域之 CORS "跨域资源共享"(Cross-origin resource sharing)POST 请求之非简单请求:
客户端代码:
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="Content-Type" content="application/json; charset=utf-8">
- <title>
- AjaxCORS
- </title>
- <style>
- body, input, select, button, h1 { font-size: 28px; line-height:1.7; }
- </style>
- </head>
- <body>
- <h1>
- 新建员工
- </h1>
- <label>
- 请输入员工姓名:
- </label>
- <input type="text" id="staffName" />
- <br>
- <label>
- 请输入员工编号:
- </label>
- <input type="text" id="staffNumber" />
- <br>
- <label>
- 请选择员工性别:
- </label>
- <select id="staffSex">
- <option>
- 女
- </option>
- <option>
- 男
- </option>
- </select>
- <br>
- <label>
- 请输入员工职位:
- </label>
- <input type="text" id="staffJob" />
- <br>
- <button id="save">
- 保存
- </button>
- <p id="createResult">
- </p>
- <script>
- function handlerResponse(response) {
- var response = JSON.parse(response);
- if (response.success) document.querySelector("#createResult").innerHTML = response.msg; // 请求成功
- else document.querySelector("#createResult").innerHTML = "出现错误:" + response.msg; // 请求失败
- }
- document.querySelector("#save").onclick = function() {
- // CORS 跨域请求(模拟跨域请求)
- // AjaxCORS.HTML 在浏览器中打开的地址为: http://localhost/AjaxCORS.HTML
- // AjaxCORS.PHP 服务器地址为: http://127.0.0.1:80/AjaxCORS.php
- var url = "http://127.0.0.1:80/AjaxCORS.php";
- var data = {
- "name": document.querySelector("#staffName").value,
- "number": document.querySelector("#staffNumber").value,
- "sex": document.querySelector("#staffSex").value,
- "job": document.querySelector("#staffJob").value
- };
- data = JSON.stringify(data);
- ajaxPOST(url, data, handlerResponse);
- }
- function ajaxPOST(url, data, callback) {
- var xhr = new XMLHttpRequest();
- xhr.open("POST", url);
- xhr.setRequestHeader("Content-type", "application/json");
- xhr.send(data);
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4 && xhr.status == 200) {
- callback(xhr.responseText);
- }
- }
- }
- </script>
- </body>
- </HTML>
服务器端代码:
- <?PHP
- // 设置页面内容是 HTML 编码格式是 utf-8
- header('Access-Control-Allow-Origin:*');
- header('Access-Control-Allow-Headers:content-type');
- // header('Access-Control-Allow-Methods:POST,GET,OPTION');
- // header('Access-Control-Allow-Credentials:true');
- // header("Content-Type: text/plain;charset=utf-8");
- header("Content-Type: application/json;charset=utf-8");
- // 定义一个多维数组, 包含员工的信息, 每条员工信息为一个数组
- $staff = array
- (
- array("name" => "洪七", "number" => "101", "sex" => "男", "job" => "总经理"),
- array("name" => "郭靖", "number" => "102", "sex" => "男", "job" => "开发工程师"),
- array("name" => "黄蓉", "number" => "103", "sex" => "女", "job" => "产品经理")
- );
- // 判断如果是 get 请求, 则进行搜索; 如果是 POST 请求, 则进行新建
- //$_SERVER 是一个超全局变量, 在一个脚本的全部作用域中都可用, 不用使用 global 关键字
- //$_SERVER["REQUEST_METHOD"]返回访问页面使用的请求方法
- if ($_SERVER["REQUEST_METHOD"] == "GET") {
- search();
- } elseif ($_SERVER["REQUEST_METHOD"] == "POST"){
- create();
- }// 创建员工
- function create(){
- // 判断信息是否填写完全
- $data=json_decode(file_get_contents('php://input'),true); // 转换成数组
- if (!$data["name"] || !$data["number"] || !$data["sex"] || !$data["job"]) {
- echo '{"success":false,"msg":" 参数错误, 员工信息填写不全 "}';
- return;
- }
- //TODO: 获取 POST 表单数据并保存到数据库
- // 提示保存成功
- echo '{"success":true,"msg":" 员工:'. $data["name"] .' 信息保存成功!"}';
- }
- ?>
运行结果:
首先是预检请求 , 使用 OPTION 方法
然后是正式请求, 使用 POST 方法:
即: 非简单请求分为 ,"预检" 请求 + 简单请求.
使用 Windows.name+iframe 来进行跨域:
原理:
通过浏览器的 Windows.name 属性实现跨域请求(每个浏览器窗口都有一个 Windows.name 属性)
原理: 无论是否同源, 只要在 "同一个窗口里", 前一个网页设置了这个属性, 后一个网页就可以读取它, 如页面 A 中
有一个 iframe,iframe.src 指向页面 B, 若页面 B 设置了 Windows.name 属性, 那么页面 A 中的那个 iframe 就能获
取到页面 B 中的 Windows.name(虽然 A 中的 iframe 能读取到 B 中的 Windows.name 属性, 但是由于 iframe 在页面 A 中,
而 iframe.src 指向页面 B, 浏览器会因为页面 A 与 iframe 不同源而阻止获取, 因此还需要设置 iframe.src 指向页面 A 所在的域)
用例:
页面 a.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <!-- 假设这个页面是域 www.aaa.com 下面的页面 A.html -->
- <title>
- a.HTML
- </title>
- </head>
- <body>
- <h2>
- domainA/a.HTML
- </h2>
- <button id="btn">
- get_data_by_iframe_window.name
- </button>
- <h3 id="data">
- </h3>
- <script>
- // 获取按钮绑定事件, 添加一个 iframe
- var btn = document.getElementById("btn");
- btn.onclick = function() {
- var ifr = document.createElement("iframe");
- // 模拟跨域请求
- // a.HTML 在浏览器中打开的地址为: http://localhost/a.HTML
- // b.HTML 需要请求的页面地址为: http://127.0.0.1:80/b.html
- ifr.src = "http://127.0.0.1/b.html";
- // 添加 iframe 到当前页面中, 并设置为不可见
- ifr.style.display = 'none';
- var body = document.getElementsByTagName("body")[0];
- body.appendChild(ifr);
- //iframe.src 会触发 iframe.onload 事件, 因此使用标记来判断 iframe.src 是否已经更改
- var flag = true;
- ifr.onload = function() {
- if (flag) {
- flag = false;
- // 为了不让浏览器阻止不同源获取 Windows.name 属性的值, 这里需要设置 iframe 与当前页面在同一个域
- //(也可以指向其他页面, 只要与创建当前 iframe 的页面在同一个域都可以)
- ifr.src = "http://localhost/a.html";
- } else {
- //contentWindow 属性返回 < iframe > 元素的 Windows 对象, 由此获取 b.HTML 页面中设置的 Windows.name 属性的值
- document.querySelector("#data").innerText = ifr.contentWindow.name;
- // 获取数据完成, 删除 iframe
- body.removeChild(ifr);
- }
- }
- }
- /**
- * 假设当前页面为 domainA/p.HTML, 里面有 iframe.src=domianA/a.HTML
- * 如果开始时候 iframe.src=domainB/b.HTML, 后来 iframe.src=domianA/a.HTML 时,
- * 那么必须是先执行完 iframe.src=domainB/b.HTML 这就语句后面的代码后, iframe 才会属于域 domainA,
- * 而在执行完 iframe.src=domainB/b.HTML 这就语句后面的代码前, iframe 依然属于域 domainB.
- *
- * 如: 假设在页面 domainA/p.HTML 中 属于域 domainA,iframe 在 p.HTML 中创建
- *
- * 首先
- * iframe.src=domainB/b.HTML
- * 执行完其他代码 现在属于域 domainB
- *
- * 然后
- * iframe.src=domianA/a.HTML 现在属于域 domainB
- * 执行完其他代码 现在属于域 domainA
- * */
- </script>
- </body>
- </HTML>
页面 b.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- b.HTML
- </title>
- </head>
- <body>
- <script>
- //b.HTML 中设置 Windows.name 的值(需要传输的数据)
- Windows.name = "我是需要传输的数据, 来自 domainB/b.html";
- </script>
- </body>
- </HTML>
运行结果:
Windows.postMessage: 跨文档通信 API(Cross-document messaging)
原理:
* HTML5 为了解决跨域问题引入了一个全新的 API: 跨文档通信 API(Cross-document messaging).
* 这个 API 为 Windows 对象新增了一个 Windows.postMessage 方法, 允许跨窗口通信, 不论这两个窗口是否同源.
* 使用方法: otherWindow.postMessage(message, targetOrigin, [transfer]);
* otherWindow:
* 其他窗口的一个引用, 比如 iframe 的 contentWindow 属性, 执行 Windows.open 返回的窗口对象, 或者是命名过或数值索引的 Windows.frames
* message:
* 将要发送到其他 Windows 的数据.
* targetOrigin:
* 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件, 其值可以是字符串 "*"(表示无限制)或者一个 URI
* 只有当目标窗口与 targetOrigin 的源完全相同时消息才能被成功发送, 只要协议, 主机名, 端口其中一项不同消息都不会被发送
- * (这个参数就显得尤为重要, 必须保证它的值与这条包含密码的信息的预期接受者的 origin 属性完全一致, 来防止密码被恶意的第三方截获)
- * [transfer]:
* 是一串和 message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方, 而发送一方将不再保有所有权.
* 父窗口和子窗口都可以通过 message 事件, 监听对方的消息.
* message 事件的事件对象 event, 提供以下三个属性.
* event.source: 记录调用 Windows.postMessage()方法的窗口信息
* event.origin: 表示调用 Windows.postMessage()方法时, 调用页面的当前状态
* event.data: 要发送到其他 Windows 的数据
用例:
页面 a.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- a.HTML
- </title>
- </head>
- <body>
- <script>
- /**
- * 本例中: 模拟跨域
- * a.HTML : http://localhost/a.HTML
- * b.HTML : http://127.0.0.1/b.html
- */
- var popup = Windows.open("http://127.0.0.1/b.html", "title b.html");
- // targetOrigin 为: http://127.0.0.1 协议: http 主机名: 127.0.0.1 端口号: 默认(80)
- // b.HTML 中的域为: http://127.0.0.1 协议: http 主机名: 127.0.0.1 端口号: 默认(80)
- // 可见目标窗口与 targetOrigin 的源完全相同
- popup.postMessage("aaaaaa 在 a.html 中 通过 postMessage 发送", "http://127.0.0.1/b.html");
- // 监听子窗口信息
- Windows.addEventListener("message",
- function(event) {
- //event.origin: 表示调用 Windows.postMessage()方法时, 调用页面的当前状态
- // 在本例中, 这里监听的是 b.HTML 中 evnet.source.postMessage()事件, event.source.postMessage()的当前状态还是属于域 http://127.0.0.1
- //console.log(event.origin); // 输出: http://127.0.0.1
- if (event.origin !== 'http://127.0.0.1') return;
- console.log(event.data);
- });
- </script>
- </body>
- </HTML>
页面 b.HTML
- <!DOCTYPE HTML>
- <HTML lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>
- b.HTML
- </title>
- </head>
- <body>
- <script>
- // 监听父窗口信息
- Windows.addEventListener("message",
- function(event) {
- //event.origin: 表示调用 Windows.postMessage()方法时, 调用页面的当前状态
- // 在本例中, 这里监听的是 a.HTML 中 popup.postMessage()事件, popup.postMessage()的当前状态还是属于域 http://localhost
- //console.log(event.origin); // 输出: http://localhost
- if (event.origin !== 'http://localhost') return;
- console.log(event.data);
- //event.source: 记录调用 Windows.postMessage()方法的窗口信息
- // 在本例中, 这里监听的是 a.HTML 中 popup.postMessage()事件, 因此这里 event.source 记录的是 a.HTML 页面窗口的信息
- // targetOrigin 为: http:localhost 协议: http 主机名: localhost 端口号: 默认(80)
- // a.HTML 中的域为: http:localhost 协议: http 主机名: localhost 端口号: 默认(80)
- // 可见目标窗口与 targetOrigin 的源完全相同
- event.source.postMessage("bbbbbb 在 b.html 中 通过 postMessage 发送", "http:localhost");
- });
- // 当然也可以使用 Windows.opener 发送信息
- Windows.opener.postMessage("bbbbbb 在 b.html 中 通过 window.opener.postMessage 发送", "http:localhost");
- </script>
- </body>
- </HTML>
运行结果:
跨子域: 修改 document.domain
原理: 两个文档上一层级的域名相同, 下一层级(或该层级以下的域名不同), 将两个文档的 document.domain 都修改为上一层级的域名(这样他们的 document.domain 就一样了)
用例:
页面一 http://a.test.com/a.html
域为: http://a.test.com
设置该页面的 document.domain=test.com
设置 document.cookie= "hello=world"
页面二 http://b.test.com/b.html
域为: http://b.test.com
设置该页面的 document.domain=test.com
这里 console.log(document.cookie) 输出结果包含 "hello=world"
通过反向代理 (Reverse Proxy)
原理: 反向代理 (Reverse Proxy) 方式是指以代理服务器来接受 Internet 上的连接请求, 然后将请求转发给内部网络上的服务器; 并将从服务器上得到的结果返回给 Internet 上请求连接的客户端, 此时代理服务器对外就表现为一个服务器. 跨域时, 页面 A , 页面 B 不同域, 但是页面 A 与代理服务器在同一个域, 页面 A 将请求发送给代理服务器(同一个域), 由代理服务器到页面 B 获取所需要的数据(跨域是浏览器阻止跨域, 服务器不存在跨域问题), 然后代理服务器将获取的数据返回给页面 A(同一个域)
用例: 无
WebSocket 跨域
原理: WebSocket 是一种通信协议, 使用 ws://(非加密)和 wss://(加密)作为协议前缀. 该协议不实行同源政策, 只要服务器支持, 就可以通过它进行跨源通信.
用例: 无
来源: https://www.cnblogs.com/go4it/p/10021551.html