Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a minimal server for AJAX in Python?

I want to create a very simple HTML/AJAX based GUI for a Python program. So the frontend is a HTML page which communicates with the program via AJAX. Can you give me a minimal implementation for the server-side using the python SimpleHTTPServer.SimpleHTTPRequestHandler?

A simple example would be a textfield and a button. When the button is pressed the content of the field is send to the server which then sends back a corresponding answer. I am aware that there are many powerful solutions for this in Python, but I would like to keep this very simple. I already found some nice examples for such a server (e.g. here), but so far I could not come up with a truly minimal one.

In case you wonder why I want to implement the GUI in such a way: My focus for this application is to display lots of data in a nice layout with only minimal interaction - so using HTML+CSS seems most convenient (and I have been already using it for non-interactive data display).

like image 926
nikow Avatar asked Dec 03 '08 11:12

nikow


People also ask

Do you need a server for AJAX?

No. Ajax isn't a thing you can install. It's a pattern for building the front end of a website. What it means is that some (or all) of the data you need for a page doesn't get sent when you initially load the page, but is loaded (asynchronously) later.

Can we use AJAX in Python?

Another way of using Ajax in Django is to use the Django Ajax framework. The most commonly used is django-dajax which is a powerful tool to easily and super-quickly develop asynchronous presentation logic in web applications, using Python and almost no JavaScript source code.

How do I run a Python script from AJAX?

$. ajax({ type: 'POST', url: "scripts/sample.py", data: {param: xyz}, //passing some input here dataType: "text", success: function(response){ output = response; alert(output); } }). done(function(data){ console. log(data); alert(data); });


1 Answers

O.K., I think I can now answer my own question. Here is an example implementation for calculating the square of a number on the server. Please let me know if there are any improvements or misconceptions.

the python server file:

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

...and the HTML file (I call it 'frontend.html', unfortunately the name has to appear in the JavaScript code as well):

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

Of course it would be much more convenient to use jQuery for the XML request, but in the interest of simplicity I'll leave it like that.

Finally an alternative implementation using WSGI (unfortunately I didn't see a way to fall back on the standard file-serving handler if the request is not a 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() 
like image 70
nikow Avatar answered Oct 12 '22 23:10

nikow