通用版父页面跨域访问iframe里面的内容解决方案,jupyter+tornado跨域通信解决方案

1、问题:获取jupyter里面的内容

现在已经将jupyter放进iframe里面,现在的问题描述为:在父页面获取iframe里面的内容,iframe里面就是jupyter,这里的父页面是自己搭建的tornado服务器打开的页面,网址为127.0.0.1:9000iframe里面的jupyter用的网址是127.0.0.1:8888,所以涉及到了跨域请求。


1.1、通用版解决跨域问题(通用的不限于tornado),可以用于其他任何场景

父页面获取iframe里面内容的解决方案如下:


实验如下:开两个tornado服务器,一个端口9000,一个端口9001

现在在9000页面要放一个iframe指向9001的一个页面,再在9000父页面打印9001iframe里面的东西是访问不了的,提示跨域了,端口不一样 




目标父页面127.0.0.1:9000访问自己iframe src=127.0.0.1:9001里面的内容

解决这个问题的方案的思路:

1、在127.0.0.1:9000页面使用js代码动态增加一个iframesrc是与127.0.0.1:9001同级目录下的一个页面127.0.0.1:9001/execB.html

2、然后先去9001创建好这个页面execB.html配置好url,保证能访问到。

3、在127.0.0.1:9001/execB.html中,去做想做的js操作(如调用127.0.0.1:9001中的一个js函数,或者改变背景色等都在这个页面进行)



原理解释:9000页面现在有两个iframe,一个访问9001,一个是动态增加的访问9001/execB.html,9000加载完后返回9001的<body><html>….</html></body>标签,此时,9001/execB.html也返回了,但是9001/execB.html里面有操作9001的DOM的js代码如:parent.window.frames[“myframe9000”].document.getElementById(“test”).innerHTML,这样就相当于9001/execB.html再操作9001里面的DOM,就能够操作成功

具体代码如下:

127.0.0.1:9000

html代码


js代码:

window.onload=function (ev) {
    function exec_iframe(){
    if(typeof(exec_obj)=='undefined'){
        exec_obj = document.createElement('iframe');
        exec_obj.name = 'tmp_frame';
        exec_obj.src = 'http://127.0.0.1:9001/execB';
        exec_obj.style.display = 'none';
        document.body.appendChild(exec_obj);//动态创建一个iframe
    }else{
        exec_obj.src = 'http://127.0.0.1:9001/execB?' + Math.random();
    }
  }

  exec_iframe()
}


127.0.0.1 :9001

html代码(目标id=notebook里面的内容被获取,被显示,颜色更改):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
test9001
<div id="notebook">
    <p>这个页面放到iframe里面,目标获取这里的内容就算成功</p>
</div>
</body>
</html>


127.0.0.1:9001/execB.html(真正做取值的js页面,被动态添加到9000页面iframe)

js代码(去操作同一个域名下的127.0.0.1:9001的内容获取id=notebook里面的内容: 

 
 
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
</html>
<script src="http://lib.baomitu.com/jquery/3.3.1/jquery.js"></script>
<script>
   //jquery操作方式,变个颜色
   // $('#notebook', window.parent.myframe.document).css("backgroundColor","red")

   //js的操作方式,变个颜色
   parent.window.frames["myframe"].document.getElementById("notebook").style.backgroundColor = "green";

   var temp = parent.window.frames["myframe"].document.getElementById("notebook").innerHRML;//取值
   console.log(temp)
</script>

至此,跨域访问成功~

2、目标:自己的tornado服务器的一个父页面(127.0.0.1:9000/test)要取得iframe里面(127.0.0.1:8888/notebooks/test2.ipynb)的jupyter服务器的值。

发现其实jupyter自身还有一层保护,通过阅读文档发现,还要去设置jupyter被引用的域名是谁。 



(同时可以阅读源码:notebook/base/handlers.py 62行开始定义了content_security_policy函数的操作,有相同描述,下文有解释。)


如果不添加上面的这串代码,在自己写的父页面里写

<iframe id="myframe" name="myframe" src="http://127.0.0.1:8888/notebooks/test2.ipynb" frameborder="1" style="" height="400" width=“720"></iframe>

将会导致下图1这里都打不开,将会显示图2这种东西,就是self指向是不对的,不允许其他的页面的iframe指向自己 


1 


2

那么添加了下面这串之后一切显示正常。但是现在的需求是获取iframe的值,然后好在tornado服务端存入数据库,好跟踪记录学生的学习情况。 





使用1种所说的解决跨域的方案。在jupyter目录下建立execB.html,让这个execB.html去操作jupyter里面的DOM获取里面的元素。本来是可以实现的。结果jupyter内部的content_security_policy定义的策略,让execB.html也成了允许范围之外的人

notebook/base/handlers.py里面说的很清楚,如下图: 



就是说,如果settings定义了headers就用它的,那我们现在是定义了的(就是上面让定义的在这里:~.jupyter/jupyter_notebook_config.py,如过不定义自己的tornado服务器的页面里的iframe显示不了,但是这里必须显示出来,不然没意义)但是现在定义了,因为execB.html也是一个动态创建的iframe,它又显示不了。现在这种跨域取值的方式因为jupyter自身安全保护的机制取不了值。只有换一种思路~~~~



3、jupyter取值通过ajax jsonp跨域将数据传给tornado服务器

我现在想在jupyter(随意打开一个jupyter notebook http://127.0.0.1:8888/notebooks/test2.ipynb)中获取了值(学生通过jupyter打印的返回结果)之后,通过更改jupyter源码,在源码中添加ajax方式,在jupyter中将获取的结果传给我自己的tornado服务端,然后就可以美滋滋的将学生操作的结果值存数据库了。

需求:将jupyter notebook中打印的结果传到自己的tornado服务端,在tornado服务端写sql语句将jupyter notebook前端页面传递过来的数据保存,方便显示到其他地方(二次开发jupyter notebook,将其结果作为一种使用jupyter的学生的操作反馈显示在网站后台)

3.1、jupyter页面采用修改源码的方式

在jupyter源码根目录下找到notebook/templates/notebook.html添加如下代码
window.onload=function () {
    //var temp_result = $("#notebook  div[class ~='selected'] .output_wrapper .output .output_text pre").text())
   var temp_result = $("#notebook .output_wrapper .output .output_text pre").text()
   console.log(temp_result)
}

3.2、添加ajax代码使用jsonp的方式做跨域请求

notebook/templates/notebook.html中添加ajax请求的代码

<script>
window.onload=function () {
    //temp.push($("#notebook  div[class ~='selected'] .output_wrapper .output .output_text pre").text())
   var temp_result = $("#notebook .output_wrapper .output .output_text pre").text()
   //console.log(temp_result)
    
   $.ajax({
       url: 'http://127.0.0.1:9000/ajaxjupyter',//http://127.0.0.1:9000/ajaxjupyter?callbackfun=jsonpCallback&temp_result=temp_result
       type: 'get',
       dataType: 'jsonp',
       jsonp:"callbackfun",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(默认为:callback)
       jsonpCallback:"jsonpCallback",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,如果定义了就success:function(){}就失效
       data: {
           temp_result:temp_result
       },
   });
}
 function jsonpCallback(data) {
           console.log(data)
       }
</script>

3.3、tornado服务端需要做接收和处理返回

class AjaxjupyterHandler(HomeHandler):
    def get(self):
        temp_result = self.get_argument("temp_result", "")
        callbackfun = self.get_argument("callbackfun", "") #接受callback的名字callbackfun=jsonpCallback

        res = dict()
        res["status"] = 0
        res["info"] = "添加成功"
        res["temp_result"] = temp_result

        self.set_header("content-type", "application/json")
        data = json.dumps(res)

猜你喜欢

转载自blog.csdn.net/tcf_jingfeng/article/details/80067491
今日推荐