您的位置:首页 > 编程语言 > Python开发

跨域ajax在线python编辑器

2017-08-25 19:13 309 查看
我打算做一个在线的python编辑器,并且是跨服务器的,不需要页面跳转的,还能支持文件上传,在这个过程中希望能学到一些新的知识。

主要功能:

在网页上有一个输入框,输入python代码之后,可以看到这段代码运行的结果。

 

附加功能:

1.      服务器上有一个专门的文件夹用来放写的代码,并且支持在该文件夹中建立多个子文件夹,用来放置多个小项目,每个文件夹中可以放置运行代码所需的文件。也可上传代码,也可查看代码,上传文件,不可访问目录外的文件。

2.      大概和spyder类似,左边是代码框,右上是目录文件,右下是输出结果,每个方框可以调整大小,可以不用页面跳转就可以运行代码。

3.      代码显示支持高亮功能,行号功能。

 

工具:

1.      云虚拟主机PHP5.5

2.      云服务器 Ubuntu16.04

3.      CodeIgniter 3.0.6

4.      uWSGI 2.0.12-5

5.      Django 1.11.4

6.      python 2.7.12

 

使用应用的版本:

1.      jQuery3.2.1(2.2.0)

2.      jquery-ui 1.12.1

3.      uploadify 3.2.1

4.      angular-filemanager 1.5.1

5.      codemirror-5.28.0

 

需要注意的是angular-filemanager会用到bootstrap,里面自带的bootstrap是3.3.6版本的,但是这个版本不支持jQuery3.X,自带的是jQuery2.2.0,但是bootstrap有新版本3.3.7,可以支持jQuery3.X。uploadify用jQ3可以,jQ2不行,但是如果不用uploadify,用jQ2也是可以的。

 

下面分别介绍在实现各个功能的过程中,逐步达到要求所使用的方法。

运行python程序部分:

1.      本域执行

2.      本域post

3.      跨域post

4.      本域json ajax post //跨域不能json ajax

5.      本域 jsonp ajax post

6.      跨域 jsonp ajax get //jsonp ajax不能post

7.      跨域 json ajax post cors //设置Access-Control-Allow-Origin头

这个功能是最基础的功能,因为涉及到两个网站的通信,所以每个部分都要分开调试。我采用了从简单到复杂的步骤,逐步实现了所需的功能。

1.      本域执行是在ubuntu系统中,可以根据给出的python代码字符串,得到该代码运行的结果,我使用的方法是popen,先将字符串存到文件中,然后使用r = os.popen('python '+path)得到结果。由于有些代码是会实时在结果中输出进度条,会有一些退格键,所以做了一个处理,使得退格键可以往前删除字符。

2.      本域post是在Django网站中,做一个页面可以提交代码,然后提交表单,返回运行结果,只需要运行代码后用json保存,然后用HttpResponse(results)返回即可。

3.      跨域post是在PHP网站中,也做一个表单,但是提交的时候是POST到Django网站的页面,然后把返回结果中的results项取出,显示在页面上。Django对跨域有csrf的限制,这里先使用csrf_exempt避免跨域消息拒绝。

4.      本域json ajax post是先在PHP网站中测试一下json方式的ajax,只需要把输入的代码实时输出到页面的另一个方框中。我使用的方法是jQuery,需要对$.ajax设置type、url,data:{code:code},dataType,成功和失败的执行函数,使用$('#text').html(msg['results']);将返回的结果输出到页面中,在本域中做一个页面是将POST的结果直接返回的即可。

5.      本域 jsonp ajax post是使用jsonp的方式发送ajax数据,原因是json方式的ajax不能跨域使用,需要修改的是dataType为jsonp,增加jsonp:”callback”和jsonpCallback:” run_python”。使用jsonp,返回值需要做一个修改,不能直接返回json结果,需要在json结果外面包一层run_python([results:”abc”]),这样就可以识别了。

6.      跨域 jsonp ajax get是因为jsonp会把发送的POST请求自动转化为GET请求,这里需要把前面的url改成Django网站的url即可实现跨域请求。

7.      跨域 json ajax post cors是因为我这个需求是提交代码,GET请求字符串长度有限制,所以必须要用POST方式传递,所以找到了cors。这个方式不是所有浏览器都支持,但是就目前来说是够用的。它的使用方法是在Django网站返回数据时,增加Access-Control-Allow-Origin头的设置,加入我PHP网站的域名,这样PHP网站就能正常接收发送过来的网页了。方法是response = HttpResponse(results) response["Access-Control-Allow-Origin"]=
“www.XXX.com” return response。因为我这里发送端使用的是json格式,所以这个方向没有被拒绝。

 

元素缩放部分:

1.      Javascript //需要看懂后自行修改

2.      Jquery UI Resizable Widget //重载resize函数,设置handles

这个功能是类似spyder中可以调整各个窗口大小的功能,需要左右和上下的缩放。

1.      我在网上搜索时第一个看到的是一段javascript代码,它支持将一个元素调整大小,鼠标移动到一个元素周围时,会变成对应的缩放的图标,鼠标移动即可改变改元素的大小。由于我需要指定某些边缘是可以移动的,所以就分析了一下它具体是怎么实现的,然后修改后可以在指定的边缘移动。我使用的代码是“Generic Resize by Erik Arvidsson”,它实现的原理是,截获鼠标按下和鼠标移动事件,有一个函数判断鼠标所在的支持resize的第一个div元素,还有一个函数是根据鼠标位置和div元素判断当前鼠标的形状。然后当鼠标按下时,如果当前鼠标是属于缩放的形状,就记录下当前的div的信息。当鼠标移动时,需要根据它所在的位置判断它的形状,如果目前有需要移动的div,要根据鼠标当前的位置和div上次所在的位置大小计算div的新的位置大小。

2.      上面的方法虽然可以实现缩放,但是写起来比较麻烦,需要把其中的resizeMe改成支持4种(resizeRight等)。原本的代码必须在div内部点击才可以调整大小,如果改成在边缘两侧都可以,有些点会有多个所在div,还要自定义优先级。如果想完美实现也是可以的,但是由于我这个页面是浮动页面,都是百分比的,有些东西我不知道怎么用js获取,如果想获取需要jQuery,所以我找了一个jQuery的方法。使用Jquery UI的Resizable Widget,通过对div增加一个class,就可以缩放它,可以限制它所在的区域,也可以通过设置handles控制它哪个方向可以缩放,还可以通过重载resize函数,使得左边的方框改变大小后右边的方框根据它的大小来调整,解决了我的问题。

 

发送文件部分:

1.      本域post

2.      本域ajax post

3.      跨域 ajax post ftp //未实现

4.      服务器端post

5.      跨域ajax post //django-flashpolicies

我一开始想的是用PHP页面把输入的代码存成文件,然后用ftp发到Django网站,后来因为不明原因上传不了文件,所以找了个发送文件的jQuery插件,uploadify。这个不明原因很多天后觉得应该是我登录的ftp用户可能权限不够,但是当时我就跳过了这个问题。

1.      本域post是PHP页面,通过post把输入框内容存到文件,用的是ci框架的方法。

2.      本域ajax post是把表单提交改成按钮绑定ajax请求。

3.      跨域 ajax post ftp是用ftp连接服务器,上传刚刚保存好的文件,这个方法应该是能用的,但是我没有实现。

4.      服务器端post是Django网站建立一个上传文件的页面,就是一段小代码,可以上传文件到指定目录,提取f=request.FILES.get('userfile'),然后 for chrunk inf.chunks(): fobj.write(chrunk)。

5.      跨域ajax post是用了一个插件uploadify,简单设置一下就可以ajax上传,还有一些小功能。但是因为跨域flash,Django网站不能读取到文件的内容,所以需要安装一个django-flashpolicies。

 

文件管理部分:

1.      本域配置angular-filemanager×2

2.      跨域django-cors-headers //因为有XMLHttpRequest

虽然实现了文件上传功能,但是因为我想弄一个界面来管理上传的文件,所以又找了一个jQuery插件angular-filemanager,恰好支持PHP和Django。PHP的后端用ftp,Django可以直接设置上传的路径。

1.      配置的过程还是不是很麻烦的,有些东西必须写在指定地方,<html data-ng-app="FileManagerApp">,<divid="filemanager" class="ng-cloak">,<angular-filemanager></angular-filemanager>。这个PHP的后端是ftp的,所以如果可以用ftp的话直接就可以跨域了。Django的直接就可以用。

2.      如果是跨域的话,Django首先需要用csrf_exempt暂时去掉csrf,但是这样还是不够。这里和之前传json的时候不一样了,就算在HttpResponse的时候增加Access-Control-Allow-Origin字段也不行。因为这个插件使用的是XMLHttpRequest来传递消息,所以接收方Django拒绝该消息。所以我安装了django-cors-headers,这个东西可以使得Django可以接收跨域的XMLHttpRequest消息,也可以设置接收哪些地方的消息,以及消息的种类,然后就可以使用了。需要修改的地方时是在发送方的参数设置里加上一列的:listUrl:
site+'list',site是Django网站。其中有两个地方PHP和Django函数名不一样,download和permissions。这个插件的很多css方面是固定的,我暂时还没有仔细看里面的内容,它和我前面用的resize的插件冲突,改变它的时候会有奇怪的表现,所以我让这个div不可调整大小了。

 

实时高亮部分:

1.      配置codemirror

选这个是因为据说它比较有名,我用的话感觉还不错,它支持的东西还是很多的,多语言,多风格,配置也比较简单。

1.      var editor = CodeMirror.fromTextArea(document.getElementById("area"), {lineNumbers: true, mode: "python"});,调整大小使用editor.setSize("100%","auto");,获取其中的文字使用varcode = editor.getValue();,绑定后textarea是空的,不能直接获取内容。需要导入对应语言的.js。

 

额外的部分:

1.      我在让两列的内容一样长时使用了一个jquery.ba-resize插件,实时监控resize。因为右边的文件管理器高度会发生变化,就往下推了,而我又没有办法拿到它变化的地方。

2.      我之前限制了左右两个区域的最小宽度,里面的内容又是按百分比宽度,所以移动到边上的话视觉效果不好,所以加了个长条型的按钮可以把某页面调整到100%宽度和恢复。本来是想弄一个折叠的,不过jQuery-UI的折叠插件有缩进,Tab插件表现更奇怪,所以以后有空再研究了,现在还挺好用的。

3.      我在做这个网站的时候,一直使用的是uWSGI直接把Django网站放上外网,隐约觉得不安全,所以接下来研究了一下nginx连接uWSGI,但是还是不太清楚怎样可以更安全。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息