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

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

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

如果你想知道为什么我想要以这种方式实现GUI:我的这个应用程序的重点是显示大量的数据在一个很好的布局,只有最less的交互 – 所以使用HTML + CSS似乎是最方便的(我已经将其用于非交互式数据显示)。

好,我想我现在可以回答我自己的问题。 以下是计算服务器上数字平方的示例实现。 请让我知道是否有任何改善或误解。

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

使用WSGI参考实现 。 从长远来看,你会更快乐。

 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请求。

感谢一个非常直观的例子@nikow我试图按照你的例子,但没有得到一个错误:

(进程:10281):GLib-CRITICAL **:g_slice_set_config:assertion'sys_page_size == 0'failed

我修改了你的代码来满足我的需求。

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

以下是基于@ nikow示例的Python 3的一个简单示例

我知道这可以有错误,如果你find它们,评论这些是什么。

代码发送string“我给你这个消息”,当你点击运行,python响应“我明白了”

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