代码之家  ›  专栏  ›  技术社区  ›  nikow

如何在Python中实现Ajax的最小服务器?

  •  37
  • nikow  · 技术社区  · 16 年前

    我想为Python程序创建一个非常简单的基于HTML/Ajax的GUI。所以前端是一个HTML页面,通过Ajax与程序通信。您能给我一个使用python的服务器端的最小实现吗 SimpleHTTPServer.SimpleHTTPRequestHandler ?

    一个简单的例子是一个文本字段和一个按钮。当按下按钮时,该字段的内容将发送到服务器,然后服务器将返回相应的答案。我知道在python中有很多这样强大的解决方案,但是我希望保持这个非常简单。 我已经为这样的服务器找到了一些很好的例子(例如 here 但到目前为止,我还不能想出一个真正的最小值。

    如果您想知道为什么我要这样实现GUI:我对这个应用程序的重点是以一个只有最小交互的漂亮布局显示大量数据-所以使用HTML+CSS似乎是最方便的(我已经使用它来显示非交互数据)。

    4 回复  |  直到 16 年前
        1
  •  50
  •   nikow    14 年前

    好吧,我想我现在可以回答我自己的问题了。下面是计算服务器上数字的平方的示例实现。如果有任何改进或误解,请告诉我。

    python服务器文件:

    import threading
    import webbrowser
    import BaseHTTPServer
    import SimpleHTTPServer
    
    FILE = 'frontend.html'
    PORT = 8080
    
    
    class TestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
        """The test example handler."""
    
        def do_POST(self):
            """Handle a post request by returning the square of the number."""
            length = int(self.headers.getheader('content-length'))        
            data_string = self.rfile.read(length)
            try:
                result = int(data_string) ** 2
            except:
                result = 'error'
            self.wfile.write(result)
    
    
    def open_browser():
        """Start a browser after waiting for half a second."""
        def _open_browser():
            webbrowser.open('http://localhost:%s/%s' % (PORT, FILE))
        thread = threading.Timer(0.5, _open_browser)
        thread.start()
    
    def start_server():
        """Start the server."""
        server_address = ("", PORT)
        server = BaseHTTPServer.HTTPServer(server_address, TestHandler)
        server.serve_forever()
    
    if __name__ == "__main__":
        open_browser()
        start_server()
    

    …和HTML文件(我称之为“frontend.html”,不幸的是名称也必须出现在javascript代码中):

    <html>
    <head>
    <title>AJAX test</title>
    </head>
    <body>
    <script type="text/javascript">
    
    function xml_http_post(url, data, callback) {
        var req = false;
        try {
            // Firefox, Opera 8.0+, Safari
            req = new XMLHttpRequest();
        }
        catch (e) {
            // Internet Explorer
            try {
                req = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (e) {
                try {
                    req = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch (e) {
                    alert("Your browser does not support AJAX!");
                    return false;
                }
            }
        }
        req.open("POST", url, true);
        req.onreadystatechange = function() {
            if (req.readyState == 4) {
                callback(req);
            }
        }
        req.send(data);
    }
    
    function test_button() {
        var data = document.test_form.test_text.value;           
        xml_http_post("frontend.html", data, test_handle)
    }
    
    function test_handle(req) {
        var elem = document.getElementById('test_result')
        elem.innerHTML =  req.responseText
    }
    
    </script>
    
    <form name=test_form>
    sqr(
    <input type="text" name="test_text" value="0" size="4">
    ) =
    <span id="test_result">0</span>
    <input type=button onClick="test_button();" value="start" title="start">
    </form>
    
    </body>
    </html>
    

    当然,使用起来会方便得多 jQuery 对于XML请求,但为了简单起见,我将像这样保留它。

    最后是一个使用wsgi的替代实现(不幸的是,如果请求不是post,我看不到返回标准文件服务处理程序的方法):

    import threading
    import webbrowser
    from wsgiref.simple_server import make_server
    
    FILE = 'frontend.html'
    PORT = 8080
    
    def test_app(environ, start_response):
        if environ['REQUEST_METHOD'] == 'POST':
            try:
                request_body_size = int(environ['CONTENT_LENGTH'])
                request_body = environ['wsgi.input'].read(request_body_size)
            except (TypeError, ValueError):
                request_body = "0"
            try:
                response_body = str(int(request_body) ** 2)
            except:
                response_body = "error"
            status = '200 OK'
            headers = [('Content-type', 'text/plain')]
            start_response(status, headers)
            return [response_body]
        else:
            response_body = open(FILE).read()
            status = '200 OK'
            headers = [('Content-type', 'text/html'),
                       ('Content-Length', str(len(response_body)))]
            start_response(status, headers)
            return [response_body]
    
    def open_browser():
        """Start a browser after waiting for half a second."""
        def _open_browser():
            webbrowser.open('http://localhost:%s/%s' % (PORT, FILE))
        thread = threading.Timer(0.5, _open_browser)
        thread.start()
    
    def start_server():
        """Start the server."""
        httpd = make_server("", PORT, test_app)
        httpd.serve_forever()
    
    if __name__ == "__main__":
        open_browser()
        start_server()
    
        2
  •  9
  •   Jurn Ho BobTurbo    9 年前

    使用 WSGI reference implementation . 从长远来看,你会更快乐。

    from wsgiref.simple_server import make_server, demo_app
    
    httpd = make_server('', 8000, demo_app)
    print "Serving HTTP on port 8000..."
    
    # Respond to requests until process is killed
    httpd.serve_forever()
    

    demo_应用程序相对容易编写,它可以处理您的Ajax请求。

        3
  •  0
  •   JonB    10 年前

    感谢您提供一个非常直观的例子@nikow 我试图遵循您的示例,但得到了一个错误:

    (进程:10281):glib critical**:g_slice_set_config:assertion'sys_page_size==0'失败

    我修改了你的代码以满足我的需要。

    webbrowser.open('file:///home/jon/workspace/webpages/frontend_example/%s' % FILE)
    // skipped the port part
    httpd = make_server("", 8080, test_app)
    // hardcoded it here.
    

    我的HTML文件必须放在Web服务器上吗? 我还没有把它放在那里!.

        4
  •  0
  •   Aditya Shankar Dark Falcon    7 年前

    下面是Python3的一个简单示例 基于@nikow的例子

    我知道这可能会有错误,如果你找到了,请评论这些错误是什么。

    代码发送字符串“I send you this message”当您单击运行时,python以“I got it”响应。

    HTML代码

    (您必须使用JS控制台进行此操作)

    <body>
    <button id="runButton">Run</button>
    <script type="text/javascript">
    function xml_http_post(url, data) {
    var req = new XMLHttpRequest();
    req.open("POST", url, true);
    req.onreadystatechange = function() {
        if (req.readyState == 4) {
        console.log(req.responseText);
        }
    }
    req.send(data);
    }
    
    function runbuttonfunc() {
        xml_http_post("frontend.html", "I sent you this message")
    }
    
    document.getElementById("runButton").onclick = runbuttonfunc;
    </script>
    </body>
    

    Python代码: 导入http.server

    FILE = 'frontend.html'
    PORT = 8000
    
    
    class TestHandler(http.server.SimpleHTTPRequestHandler):
        """The test example handler."""
    
        def do_POST(self):
            """Handle a post request by returning the square of the number."""
            print(self.headers)
            length = int(self.headers.get_all('content-length')[0])
            print(self.headers.get_all('content-length'))
            data_string = self.rfile.read(length)
            print(data_string)
            self.send_response(200)
            self.send_header("Content-type", "text/plain")
            self.end_headers()
            self.flush_headers()
            self.wfile.write("I got it!".encode())
    
    
    def start_server():
        """Start the server."""
        server_address = ("", PORT)
        server = http.server.HTTPServer(server_address, TestHandler)
        server.serve_forever()
    
    start_server()