1. 概述
1.1 問題描述
使用者想要實現在自己的 OA 系統裏點選按鈕,就能觸發我們的報表的提交事件。但是如果報表和他們的 OA 不在一個應用中,會存在 JS 跨域呼叫的權限問題,這個問題該如何解決呢?
1.2 實現思路
如果是谷歌和火狐等支援 HTML5 的瀏覽器,則可透過 postMessage() 方法即可跨域通訊;
如果是 IE8 之前等不支援 HTML5 的,則透過一個可以跨域的全局屬性 window.name,外部應用可以存取並修改 iframe 中的 window.name。然後 iframe 中的頁面每隔一段時間檢查一下,如果 window.name 的值變化了則做出相應的事件迴應。
本文將這兩種方法放在一起,這樣不論在 火狐 或者 IE8 等瀏覽器下都可以實現跨域提交,避開了瀏覽器的問題。
注:本文僅能用於 HTML5 瀏覽器或者子域不同的情況,對於頂級域不同而且不支援 H5 的瀏覽器的情況不適用。
比如在 IE8 裏面從 www.ttt.com --->org.aaa.com 就不能用。
2. 範例
這裏使用提交_g().writeReport()做示範,其他 JS 也都支援。
2.1 範本設定
在需要進行填報的範本新增「載入結束」事件。
開啟 填報可暫存.cpt 範本,該範本在%FR_HOME%\webapps\webroot\WEB-INF\reportlets\demotw\form目錄下。
將該範本另存在%FR_HOME%\webapps\webroot\WEB-INF\reportlets\doc\JS\分頁預覽JS實體目錄下,重新命名為CrossSubmit.cpt。
點選範本>範本Web屬性>填報頁面設定,在「事件設定」下新增「載入結束」事件。具體情況如下圖所示:
其中程式碼如下所示:
if(!window.a){
function send(val){
sendMessage(val);
}
(function(win, doc){
var ifr = win.parent;
var cb = function(msg){
eval(msg);
};
var sendMessage = function(){
if(win.postMessage){
if (win.addEventListener) {
win.addEventListener("message",function(e){
cb.call(win,e.data);
},false);
}else if(win.attachEvent) {
win.attachEvent("onmessage",function(e){
cb.call(win,e.data);
});
}
return function(data){
ifr.postMessage(data,'*');
};
}else{
var hash = '';
setInterval(function(){
if(win.name!==hash){
hash = win.name;
cb.call(win,hash);
}
},200);
return function(data){
ifr.name = data;
};
}
}
win.sendMessage = sendMessage();
})(window, document);
window.a=1;
}
2.2 提交頁面設定
1)在本地建立 test.html,此時 test.html 與我們報表範本是兩個不同的域,在 test.html 中點跨域提交按鈕,呼叫 send("_g().writeReport()") 則可以實現跨域提交。
test.html 的程式碼如下所示:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<script>
window.name="aaaa";
function f(){
}
</script>
<body>
<input type="button" name="aa" value="跨域提交" onclick="send('_g().writeReport()')"/>
<iframe name="iframeA" id="iframeA" width="900" height="400" src="http://localhost:8075/webroot/decision/view/report?viewlet=doctw/JS/分頁預覽JS實體/CrossSubmit.cpt&op=write"></iframe>
<script type="text/javascript">
//document.getElementById('host').innerHTML = location.host;
function send(msg){
sendMessage(msg);
}
(function(win, doc){
var ifr = doc.getElementById('iframeA').contentWindow;
var cb = function(json){
eval(json);
};
var sendMessage = function(){
if(win.postMessage){
if (win.addEventListener) {
win.addEventListener("message",function(e){
cb.call(win,e.data);
},false);
}else if(win.attachEvent) {
win.attachEvent("onmessage",function(e){
cb.call(win,e.data);
});
}
return function(data){
ifr.postMessage(data,'*');
};
}else{
var hash = '';
setInterval(function(){
if (win.name !== hash) {
hash = win.name;
cb.call(win, hash);
}
}, 200);
return function(data){
ifr.name = data;
};
}
};
win.sendMessage = sendMessage();
})(window, document);
</script>
</body>
</html>
2)將建立好的 test.html 放到 %FR_HOME%\webapps\webroot\help\page_demo 路徑下,如下圖所示:
3)開啟資料決策平台,點選管理系統>安全管理>安全防護>Security Headers>進階設定,關閉點選劫持攻擊防護按鈕。如下圖所示:
若不關閉這個按鈕,預覽時將會出現如下圖所示的錯誤:
3. 效果查看
雙擊 test.html 檔案,即可在瀏覽器中查看範本並進行跨域提交,如下圖所示:
4. 已完成範本
已完成範本,請參見: %FR_HOME%\webapps\webroot\WEB-INF\reportlets\doctw\JS\分頁預覽JS實體\CrossSubmit.cpt
點選下載範本: CrossSubmit.cpt
點選下載 test.html 檔案:test.html