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

时间:2008-12-03 11:37:28

标签: python ajax user-interface

我想为Python程序创建一个非常简单的基于HTML / AJAX的GUI。所以前端是一个HTML页面,它通过AJAX与程序通信。你能使用python SimpleHTTPServer.SimpleHTTPRequestHandler

给我一​​个服务器端的最小实现

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

如果你想知道我为什么要以这种方式实现GUI:我对这个应用程序的关注是在很好的布局中显示大量数据,只需要很少的交互 - 所以使用HTML + CSS似乎最方便(而且我已经将它用于非交互式数据显示)。

4 个答案:

答案 0 :(得分:51)

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

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()

答案 1 :(得分: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_app相对容易编写;它处理您的Ajax请求。

答案 2 :(得分:0)

感谢一个非常直观的例子@nikow 我试图按照你的例子,但确实收到了错误:

(进程:10281):GLib-CRITICAL **:g_slice_set_config:断言&#39; sys_page_size == 0&#39;失败

我修改了您的代码以满足我的需求。

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文件是否必须放在网络服务器上? 我还没有把它放在那里!。

答案 3 :(得分:0)

这是Python 3的一个简单示例 基于@nikow的例子

我知道这可能有错误,如果你找到它们会发表评论。

代码发送字符串&#34;我发给你这条消息&#34;当你点击运行时,python会回复&#34;我得到它&#34;

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()