如何使用 javascript 客户端设置 Python 服务器端

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11727145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 14:08:08  来源:igfitidea点击:

How to set up Python server side with javascript client side

javascriptpython

提问by Nikhil Unni

So there is already a Python program set up that runs on the console that I must build upon. I will be building a web GUI interface for the application using Javascript. How would I:

所以已经有一个 Python 程序设置在我必须构建的控制台上运行。我将使用 Javascript 为应用程序构建一个 Web GUI 界面。我将如何:

a. Go about handling the input/output of this Python program without touching the original code.

一个。在不接触原始代码的情况下处理这个 Python 程序的输入/输出。

b. Go about sending console-line inputs to the Python program via Javascript calls. I've looked into raw HTTP requests/AJAX, but I'm not sure how exactly I would go about sending that as input to the Python program.

湾 通过 Javascript 调用将控制台行输入发送到 Python 程序。我已经研究了原始 HTTP 请求/AJAX,但我不确定如何将其作为输入发送到 Python 程序。

采纳答案by Logan

a. To handle input/output of the program: Pexpect. It's fairly easy to use, and reading some of the examples distributed with it should teach you enough to get the basics down.

一个。处理程序的输入/输出:Pexpect。它相当容易使用,阅读一些随它分发的示例应该可以教会您足够的基础知识。

b. Javascript interface:

湾 Javascript接口:

Well, I use gevent and it's built-in WSGI server. (look up what a WSGI server(another) is). I should note that this program will keep a state, so you can manage your open sessions by returning a session ID to your javascript client and storing your pexpect session in a global variable or some other container so that you can complete the program's input and output across multiple independent AJAX requests. I leave that up to you, however, as that is not as simple.

好吧,我使用 gevent 并且它是内置的 WSGI 服务器。(查看WSGI 服务器另一个)是什么)。我应该注意到这个程序将保持一个状态,因此您可以通过将会话 ID 返回到您的 javascript 客户端并将您的 pexpect 会话存储在全局变量或其他容器中来管理您打开的会话,以便您可以完成程序的输入和输出跨多个独立的 AJAX 请求。然而,我把这留给你,因为这并不那么简单。

All my example will do is put the POST request in some after clicking something of your choice. (it won't actually work because some of the variables are not set. Set them.)

我的所有示例都会做的是在单击您选择的某些内容后将 POST 请求放入某些内容中。(它实际上不会工作,因为一些变量没有设置。设置它们。)

Heres the relevant parts:

以下是相关部分:

<!-- JavaScript -->
<script src="jquery.js"></script>
<script type="text/javascript">
function toPython(usrdata){
    $.ajax({
        url: "http://yoursite.com:8080",
        type: "POST",
        data: { information : "You have a very nice website, sir." , userdata : usrdata },
        dataType: "json",
        success: function(data) {
            <!-- do something here -->
            $('#somediv').html(data);
        }});
$("#someButton").bind('click', toPython(something));
</script>

Then the server:

然后服务器:

# Python and Gevent
from gevent.pywsgi import WSGIServer
from gevent import monkey
monkey.patch_all() # makes many blocking calls asynchronous

def application(environ, start_response):
    if environ["REQUEST_METHOD"]!="POST": # your JS uses post, so if it isn't post, it isn't you
        start_response("403 Forbidden", [("Content-Type", "text/html; charset=utf-8")])
        return "403 Forbidden"
    start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
    r = environ["wsgi.input"].read() # get the post data
    return r

address = "youraddresshere", 8080
server = WSGIServer(address, application)
server.backlog = 256
server.serve_forever()

If your program is Object Oriented, it'd be fairly easy to integrate this. EDIT: Doesn't need to be object oriented. and I have now included some Pexpect code

如果您的程序是面向对象的,那么集成它会相当容易。编辑:不需要面向对象。我现在已经包含了一些 Pexpect 代码

global d
d = someClass()
def application(environ, start_response):
    # get the instruction
    password = somethingfromwsgi # read the tutorials on WSGI to get the post stuff
    # figure out WHAT to do
    global d
    success = d.doSomething()
    # or success = funccall()
    prog = pexpect.spawn('python someprogram.py')
    prog.expect("Password: ")
    prog.sendline(password)
    i = prog.expect(["OK","not OK", "error"])
    if i==0:
        start_response("200 OK", [("Content-Type", "text/html; charset=utf-8")])
        return "Success"
    elif i==1:
        start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
        return "Failure"
    elif i==2:
        start_response("500 Internal Server Error", [("Content-Type", "text/html; charset=utf-8")])
        return "Error"

Another option I suggest is Nginx + uWSGI. If you would prefer that, I can give you some examples of that as well. It gives you the benefit of incorporating the webserver into the setup.

我建议的另一个选择是 Nginx + uWSGI。如果你愿意,我也可以给你一些例子。它为您提供了将网络服务器合并到设置中的好处。

回答by jfs

To pass transparently your data from javascript to external Python program you could use WebSocket protocol to connect your server and javascript, and use stdin/stdout to communicate with the external program from the server.

要将数据从 javascript 透明地传递到外部 Python 程序,您可以使用 WebSocket 协议连接服务器和 javascript,并使用 stdin/stdout 与来自服务器的外部程序进行通信。

Here's an example Python program client.py:

这是一个示例 Python 程序client.py

#!/usr/bin/env python
"""Convert stdin to upper case."""
for line in iter(raw_input, 'quit'):
    print line.upper()

I've created a server using code from hello world websocket exampleand SO answer about how to create a new process on each incoming connection and to redirect all input data to the process' stdin:

我已经使用hello world websocket 示例中的代码创建了一个服务器,并回答了有关如何在每个传入连接上创建新进程并将所有输入数据重定向到进程的 stdin 的答案:

#!/usr/bin/python
"""WebSocket CLI interface."""
import sys
from twisted.application import strports # pip install twisted
from twisted.application import service
from twisted.internet    import protocol
from twisted.python      import log
from twisted.web.server  import Site
from twisted.web.static  import File

from txws import WebSocketFactory # pip install txws


class Protocol(protocol.Protocol):
    def connectionMade(self):
        from twisted.internet import reactor
        log.msg("launch a new process on each new connection")
        self.pp = ProcessProtocol()
        self.pp.factory = self
        reactor.spawnProcess(self.pp, sys.executable,
                             [sys.executable, '-u', 'client.py'])
    def dataReceived(self, data):
        log.msg("redirect received data to process' stdin: %r" % data)
        self.pp.transport.write(data)
    def connectionLost(self, reason):
        self.pp.transport.loseConnection()

    def _send(self, data):
        self.transport.write(data) # send back


class ProcessProtocol(protocol.ProcessProtocol):
    def connectionMade(self):
        log.msg("connectionMade")
    def outReceived(self, data):
        log.msg("send stdout back %r" % data)
        self._sendback(data)
    def errReceived(self, data):
        log.msg("send stderr back %r" % data)
        self._sendback(data)
    def processExited(self, reason):
        log.msg("processExited")
    def processEnded(self, reason):
        log.msg("processEnded")

    def _sendback(self, data):
        self.factory._send(data)


application = service.Application("ws-cli")

_echofactory = protocol.Factory()
_echofactory.protocol = Protocol
strports.service("tcp:8076:interface=127.0.0.1",
                 WebSocketFactory(_echofactory)).setServiceParent(application)

resource = File('.') # serve current directory INCLUDING *.py files
strports.service("tcp:8080:interface=127.0.0.1",
                 Site(resource)).setServiceParent(application)

The web-client part, sendkeys.html:

网络客户端部分,sendkeys.html

<!doctype html>
<title>Send keys using websocket and echo the response</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js">
</script>
<script src="sendkeys.js"></script>
<input type=text id=entry value="type something">
<div id=output>Here you should see the typed text in UPPER case</div>

and sendkeys.js:

sendkeys.js

// send keys to websocket and echo the response
$(document).ready(function() {
    // create websocket
    if (! ("WebSocket" in window)) WebSocket = MozWebSocket; // firefox
    var socket = new WebSocket("ws://localhost:8076");

    // open the socket
    socket.onopen = function(event) {
    socket.send('connected\n');

    // show server response
    socket.onmessage = function(e) {
        $("#output").text(e.data);
    }

    // for each typed key send #entry's text to server
    $("#entry").keyup(function (e) {
        socket.send($("#entry").attr("value")+"\n");
    });
    }
});

To try it:

试试看:

  • download this gist
  • install twisted, txws:

    $ pip install twisted txws
    
  • run:

    $ twistd -ny wscli.py
    
  • visit http://localhost:8080/

  • click on sendkeys.htmland type something

  • 下载这个要点
  • 安装twistedtxws

    $ pip install twisted txws
    
  • 跑:

    $ twistd -ny wscli.py
    
  • 访问 http://localhost:8080/

  • 点击sendkeys.html并输入一些东西

回答by Colin Dunklau

You probably want Flask, along with the json module.

您可能需要Flask以及json 模块

Djangois another option, but is probably too high-level for your needs.

Django是另一种选择,但对于您的需求来说可能太高级了。

回答by Ivan P

This depends on what sort of application you are wrapping and on how your GUI options translate into application commands. But you have two goals here:

这取决于您包装的应用程序类型以及您的 GUI 选项如何转换为应用程序命令。但是你在这里有两个目标:

  1. Writing a wrapper to allow you to read your program's output and provide it input.

  2. Making a web-server to receive GUI events and convert them to commands to pass to your "wrapper"

  1. 编写包装器以允许您读取程序的输出并为其提供输入。

  2. 制作一个网络服务器来接收 GUI 事件并将它们转换为命令以传递给您的“包装器”

I have done something like what you need to do.

我已经做了类似你需要做的事情。

  1. Essentially you need to turn socket streams into discreet commands. The defacto tool for this is expect, and any of it's wrappers (I've used pexpect, the Python wrapper, and had a good experience with it).

  2. This part might not be simple. The problem is that your underlying program is persistently running, and so your web-server should be statefull to know about the program across requests. The other option is for your web-server to simply re-attach to the process and issue it commands, and send back a response when it is encountered in the stdout stream, but you might end up with long response times depending on how fast the program is. Also there is the mismatch that AJAX requests are asynchronous, while your underlying program is synchronous. So yes, this can get quite complex. It really depends on your program. If you could add some details about what the program and the GUI are like, it'd help.

  1. 本质上,您需要将套接字流转换为谨慎的命令。事实上,这个工具是expect,以及它的任何包装器(我使用过pexpect,Python 包装器,并且对它有很好的体验)。

  2. 这部分可能并不简单。问题是您的底层程序一直在运行,因此您的 Web 服务器应该是有状态的,以便跨请求了解该程序。另一种选择是让您的 Web 服务器简单地重新附加到进程并发出命令,并在 stdout 流中遇到响应时发回响应,但最终响应时间可能会很长,具体取决于响应的速度程序是。此外,AJAX 请求是异步的,而您的底层程序是同步的,这是不匹配的。所以是的,这可能会变得非常复杂。这真的取决于你的程序。如果您可以添加一些有关程序和 GUI 的详细信息,它会有所帮助。