1. 概述
1.1 跨域概念
域(Domain)是 Windows 網路中獨立運作的單位,域之間相互存取則需要建立信任關係(即 Trust Relation)。信任關係是連結在域與域之間的橋樑。當一個域與其他域建立了信任關係後,2 個域之間不但可以按需要相互進行管理,還可以跨網分配檔案和印表機等裝置資源,使不同的域之間實現網路資源的共享與管理。
簡而言之,跨域存取,就是 A 網站的 JavaScript 程式碼試圖存取 B 網站,包括提交內容和獲取內容。由於安全原因,跨域存取是被各大瀏覽器所預設禁止的。
詳細列表如下圖所示:
URL | 說明 | 是否允許通訊 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js | 同一域名下 | 允許 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js | 同一域名下,不同資料夾 | 允許 |
http://www.a.com:8000/a.js http://www.a.com/b.js | 同一域名下,不同埠 | 不允許 |
http://www.a.com/a.js https://www.a.com/b.js | 同一域名下,不同協定 | 不允許 |
http://www.a.com/a.js http://70.32.92.74/b.js | 域名和域名對應 IP | 不允許 |
http://www.a.com/a.js http://script.a.com/b.js | 主域相同,子域不同 | 不允許 |
http://www.a.com/a.js http://a.com/b.js | 同一域名下,不同二級域名(同上) | 不允許(Cookie 情況下也不允許存取) |
http://www.cnblogs.com/a.js http://www.a.com/b.js | 不同域名 | 不允許 |
注:如果是協定和埠造成的跨域問題“前台”是無能為力的;
在跨域問題上,域僅僅是透過“URL 的標頭”來識別而不會去嘗試判斷相同的 IP 地址對應着兩個域或兩個域是否在同一個 IP上。
1.2 問題描述
存取伺服器下的一個 HTML 檔案,該檔案中嵌了一個 FineReport 的範本檔案,但是該範本檔案在另外一個域中,如果直接存取 HTML 檔案,是無法呼叫到 FineReport 範本檔案的這就涉及到跨域問題,該如何解決呢?
1.3 解決思路
透過一箇中轉檔案來實現跨域通訊,因為 JS 可以執行不同域下的檔案,那麼就可以將該被執行檔案放置需要通訊的那個不同的域下,該被執行檔案可以對同一個域下的所有資料進行操作。
2. 範例
在 上一節 中介紹了同一伺服器,同一埠號不同工程下的跨域存取,是專門針對 IE8 的解決方案,在本章節就介紹同一機器下,不同埠號之間的 JS 跨域存取。
埠號為 8080 的伺服器下的 lo1.html 中嵌入了一個 iframe,iframe中展現的是埠號為 8081 下的一個 FineReport 範本檔案 test.frm,test.frm 裏面有一個正文框和一個按鈕,在點選 test.frm 裏面的按鈕時,則可將正文框中的內容賦給lo1.html中的正文框。
2.1 Web 伺服器準備
在機器下部署兩個 Tomcat 伺服器,Tomcat1 和 Tomcat2,Tomcat1 使用預設埠號 8080,Tomcat2 將 http 存取埠號改為 8081,shutdown 埠號(預設 8005)改為 8055,8009 埠號改為 8099,操作參見文檔:Tomcat 埠配置
2.2 Tomcat1
在 Tomcat1 下部署 webroot 工程,該工程%FR_HOME%/webapps/webroot/下需要放三個檔案,lol.html,proxy.html,proxy.js。
proxy.html 是中轉的 HTML,它和 lol.html(主頁面)在同一個域,其作用就是執行 proxy.js,並被 test.frm 動態載入。而 proxy.js 是其他域的傳來的資料對 lol.html 的處理。
2.2.1 lol.html 程式碼
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Language" content="zh-CN" />
<meta content="all" name="robots" />
<title>跨域</title>
<body>
<input id="main" type="text" value="I'm main" />
<iframe src="http://192.168.101.226:8081//webroot/decision/view/report?viewlet=test.frm" height="300" width="500"></iframe>
</body>
</head>
</html>
2.2.2 proxy.html 程式碼
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Language" content="zh-CN" />
<meta content="all" name="robots" />
<title>代理</title>
<script type="text/javascript" src="proxy.js"> </script>
<body> </body>
</head>
</html>
2.2.3 proxy.js 程式碼
var doc = window.top.document;
doc.getElementById("main")
.value = getQueryStringRegExp("tarValue");
function getQueryStringRegExp(name) {
var reg = new RegExp("(^|\\?|&)" + name + "=([^&]*)(\\s|&|$)", "i");
if (reg.test(location.href)) {
return unescape(RegExp.$2.replace(/\+/g, " "));
} else {
return "";
}
};
2.3 Tomcat2
在 Tomcat2 伺服器下部署工程 webroot,將報表工程獨立部署過去,刪除 reportlet 下的所有範本檔案,建立一個決策報表檔案 test.frm。
將一個參數介面組件拖到 body 區域,裏面拖進去一個正文空間一個按鈕空間,並給按鈕元件新增點選事件,如下圖所示:
給 button0 增加點選事件,程式碼如下:
var tarValue = this.options.form.getValueByName("textEditor0");
//這裏根據是報表用不同的方式,自己定義
var url = "http://192.168.101.226:8080/webroot/proxy.html?_=" + new Date()
.getTime() + "&tarValue=" + tarValue;
alert(url);
var iframe = document.getElementById('proxy');
if (!iframe) {
// 如果iframe還沒有加進去,則加進去
iframe = document.createElement('iframe');
document.getElementsByTagName('head')[0].appendChild(iframe);
iframe.setAttribute('name', 'proxy');
iframe.setAttribute('id', 'proxy');
}
iframe.setAttribute('src', url);
注:上面的所有程式碼中涉及到的 IP 地址都要改成自己的 IP 地址,不能用 localhost 。
2.4 效果查看
同時啟動 Tomcat1 和 Tomcat2,在瀏覽器端開啟 lo1.html,即在地址欄輸入http://192.168.101.226:8080/webroot/lol.html,如下圖所示:
在 iframe 中的正文框中輸入 FineReport,點選 button0 按鈕,會看到最左側的正文框(顯示 I'm main 的正文框)只中也會顯示 FineReport,這就實現了 JS 跨域,如下圖所示: