it-swarm.com.de

So implementieren Sie einen minimalen Server für AJAX in Python?

Ich möchte eine sehr einfache HTML/AJAX-basierte Benutzeroberfläche für ein Python-Programm erstellen. Das Frontend ist also eine HTML-Seite, die über AJAX mit dem Programm kommuniziert. Können Sie mir eine minimale Implementierung für die Serverseite mit dem Python SimpleHTTPServer.SimpleHTTPRequestHandler geben?

Ein einfaches Beispiel wäre ein Textfeld und eine Schaltfläche. Wenn der Knopf gedrückt wird, wird der Inhalt des Feldes an den Server gesendet, der dann eine entsprechende Antwort zurücksendet. Ich bin mir bewusst, dass es in Python viele leistungsstarke Lösungen dafür gibt, aber ich möchte dies sehr einfach halten. Ich habe bereits einige nette Beispiele für einen solchen Server gefunden (z. B. hier ), aber bisher konnte ich kein wirklich minimales finden.

Für den Fall, dass Sie sich fragen, warum ich die GUI so implementieren möchte: Mein Fokus für diese Anwendung liegt auf der Anzeige vieler Daten in einem ansprechenden Layout mit nur minimaler Interaktion - daher scheint die Verwendung von HTML + CSS am bequemsten (und das war ich auch schon Verwendung für nicht interaktive Datenanzeige).

37
nikow

OK, ich glaube, ich kann jetzt meine eigene Frage beantworten. Hier ist eine Beispielimplementierung zur Berechnung des Quadrats einer Zahl auf dem Server. Bitte lassen Sie mich wissen, wenn es Verbesserungen oder Missverständnisse gibt.

die Python-Server-Datei:

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 __== "__main__":
    open_browser()
    start_server()

... und die HTML-Datei (ich nenne 'frontend.html', leider muss der Name auch im JavaScript-Code erscheinen):

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

Natürlich wäre es viel bequemer, jQuery für die XML-Anfrage zu verwenden, aber im Interesse der Einfachheit lasse ich es so.

Zum Schluss noch eine alternative Implementierung mit WSGI (leider sah ich keinen Weg, auf den standardmäßigen File-Serving-Handler zurückzugreifen, wenn die Anforderung kein POST ist):

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 __== "__main__":
    open_browser()
    start_server()
50
nikow

Verwenden Sie die WSGI-Referenzimplementierung . Auf lange Sicht wirst du glücklicher sein.

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

Die demo_app ist relativ leicht zu schreiben. es verarbeitet Ihre Ajax-Anfragen.

9
S.Lott

Hier ist ein einfaches Beispiel für Python 3 Basierend auf @ nikows Beispiel

Ich weiß, dass dies Fehler haben kann, kommentieren Sie, wenn Sie sie finden.

Der Code sendet die Zeichenfolge "Ich habe Ihnen diese Nachricht gesendet", wenn Sie auf "Ausführen" klicken. Python antwortet mit "Ich habe es".

HTML Quelltext

(Sie müssen dafür die js-Konsole verwenden)

<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-Code: Import 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()
0
Aditya Shankar

Vielen Dank für ein sehr intuitives Beispiel @nikow Ich habe versucht, Ihrem Beispiel zu folgen, erhielt jedoch eine Fehlermeldung:

(Prozess: 10281): GLib-CRITICAL **: g_slice_set_config: Die Assertion 'sys_page_size == 0' ist fehlgeschlagen

Ich habe Ihren Code an meine Bedürfnisse angepasst.

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

muss meine HTML-Datei auf den Webserver gestellt werden Ich habe sie noch nicht dort abgelegt!.

0
JonB