Подтвердить что ты не робот

Как реализовать минимальный сервер для AJAX в Python?

Я хочу создать очень простой графический интерфейс на основе HTML/AJAX для программы Python. Таким образом, интерфейс - это HTML-страница, которая связывается с программой через AJAX. Можете ли вы дать мне минимальную реализацию для серверной части, используя python SimpleHTTPServer.SimpleHTTPRequestHandler?

Простым примером может быть текстовое поле и кнопка. Когда кнопка нажата, содержимое поля отправляется на сервер, который затем отправляет ответный ответ. Я знаю, что в Python есть много мощных решений, но я хотел бы сохранить это очень просто. Я уже нашел несколько хороших примеров для такого сервера (например, здесь), но до сих пор я не мог придумать поистине минимальный.

В случае, если вы задаетесь вопросом, почему я хочу реализовать графический интерфейс таким образом: мой фокус для этого приложения заключается в отображении большого количества данных в красивой макете с минимальным взаимодействием, поэтому использование HTML + CSS кажется наиболее удобным (и я уже использовали его для отображения неинтерактивных данных).

4b9b3361

Ответ 1

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

Ответ 2

Используйте ссылку на 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.

Ответ 3

Спасибо за очень интуитивный пример @nikow Я пытался следовать вашему примеру, но получил ошибку:

(process: 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 файл быть помещен на веб-сервер? Я еще не добавил его!

Ответ 4

Вот простой пример для Python 3 основанный на примере @nikow

Я знаю, что это может иметь ошибки, комментировать, что это такое, если вы их найдете.

Код отправляет строку "Я отправил вам это сообщение", когда вы нажимаете run, 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:   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()