简体   繁体   中英

create simple HTTP server and stop when user visits specific URL

I want to create and run an HTTP server in the background and listen to the last visited URL. If the user visits a specific URL (eg /stop-server), I want to stop the server.

Since there are so many options, I am confused what I should use and I don't want to use complicated libraries for something so simple.

※ I am using (and I want to use) PySide6 v6.3 for this project by the way.

I made a working example using "http.server", but I am not happy with it because it looks a little tricky to me, so I am worried about "unexpected" bugs.

What library should I use?

update:

The tricky parts I am considering are:
1- wrapping the HttpServer class in a function for using callbacks, I am not sure if it is good thing to do

2- using QThreads (instead of QRunnable) and forcing it to terminate because I can not shutdown the web_server properly.
(the shutdown() method (of web_server) doesn't terminate the QThread, so I have to do it manually.)

3- I am not using the built-in Qt method. There is QHttpServer but it's only available from version 6.4.

from http.server import BaseHTTPRequestHandler, HTTPServer

from PySide6.QtCore import QThread, QRunnable, Slot, QThreadPool, Signal, QObject
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout

_HOST = "localhost"
_PORT = 9999


def server_handler(callback):
    class HttpServer(BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()

            self.wfile.write(bytes(f"<p>{self.path}</p>", "utf-8"))

            if self.path == "/stop-server":
                callback()

    return HttpServer


class Worker(QThread):
    finished = Signal(bool)

    def __init__(self):
        super(Worker, self).__init__()
        self.web_server = None
        self.setTerminationEnabled(True)

    @Slot()
    def run(self) -> None:
        http_server = server_handler(self.close_server)
        self.web_server = HTTPServer((_HOST, _PORT), http_server)
        print("Server started ", f"http://{_HOST}:{_PORT}")
        self.web_server.serve_forever()

    def close_server(self):
        print("Server stopped")
        self.finished.emit(True)
        self.web_server.server_close()


class Application(QWidget):

    def __init__(self):
        super(Application, self).__init__()

        self.threadpool = QThreadPool()
        self.server = Worker()
        self.server.finished.connect(self.finished)
        self.server.start()

        self.show()

    def finished(self):
        print("terminate")
        self.server.terminate()


if __name__ == '__main__':
    app = QApplication()
    _ = Application()
    app.exec()

Flask could be a very simple solution for you to quickly and easily spin up a server to test this out on your machine.

From Flask's quickstart guide (plus a route added for your use case):

hello.py:

from flask import Flask, request
app = Flask(__name__)


@app.route('/')
def hello_world():
    return 'Hello, World!'


@app.route('/server-shutdown')
def shutdown():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()
    return "Shutting down..."

and then on the command line in the same directory:

$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

then try curl http://127.0.0.1:5000/ and curl http://127.0.0.1:5000/server-shutdown -- you'll see that the latter shuts down the app.

There are many great guides to doing more with flask and great support for it out there. IMO the best is hackers and slackers for a quick intro and Miguel Grinberg's series are incredible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM