历史版本20 :跨域调用 JS 返回文档
编辑时间: 内容长度:图片数:目录数: 修改原因:

目录:

1. 问题描述编辑

用户想要实现在自己的 OA 系统里点击按钮,就能触发我们的报表的提交事件。但是如果报表和他们的 OA 不在一个应用中,会存在 JS 跨域调用的权限问题,这个问题该如何解决呢?

2. 实现思路编辑

如果是谷歌和火狐等支持 HTML5 的浏览器,则可通过 postMessage() 方法即可跨域通信;如果是 IE8 之前等不支持 HTML5 的,则通过一个可以跨域的全局属性 window.name,外部应用可以访问并修改 iframe 中的 window.name。然后 iframe 中的页面每隔一段时间检查一下,如果 window.name 的值变化了则做出相应的事件响应。下面我们将这两种方法放在一起,这样不论在 FireFox 或者 IE8 等浏览器下都可以实现跨域提交,避开了浏览器的问题。

注:只能用于 H5 浏览器或者子域不同的情况,对于顶级域不同而且不支持 H5 的浏览器的时候就不行了,比如在 IE8 里面从 www.ttt.com --->org.aaa.com 就不能用。

3. 解决方案编辑

这里使用提交_g().writeReport()做演示,其他 js 也都支持。

3.1 模板设置

在需要进行填报的模板添加「加载结束」事件。

打开 填报可暂存.cpt 模板,该模板在%FR_HOME%\webapps\webroot\WEB-INF\reportlets\demo\form目录下。

将该模板另存在%FR_HOME%\webapps\webroot\WEB-INF\reportlets目录下,重命名为CrossSubmit.cpt。

点击模板>模板Web属性>填报页面设置,在「事件设置」下添加「加载结束」事件。具体情况如下图所示:

5.png

其中代码如下所示:

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;
}

3.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=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  路径下,如下图所示:

6.png

3)关闭点击劫持攻击防护按钮。具体步骤如下图所示:

12.png

若不关闭这个按钮,将会出现如下图所示的错误:

13.png


3.3 效果查看

66.png

模板下载:

CrossSubmit.cpt

test.html