Un handler pentru fiecare rută
Rutarea decide ce cod răspunde la ce cerere. Modulul standard http.server nu are un router încorporat — și nici nu este nevoie de unul în cazurile obișnuite: do_GET se uită la self.path și direcționează cererea.
Un parametru de cale este bucata din URL care reprezintă date: în /users/7, acesta este 7. Împărțirea căii în segmente ți-l oferă: "/users/7".strip("/").split("/") dă ['users', '7']. Framework-urile adaugă deasupra routere bazate pe șabloane, dar în spate fac exact acest lucru.
Rute și valori din cale
Două rute: lista la /users și un singur utilizator la /users/7. Segmentul cu id-ul este parametrul de cale — partea din URL care transportă date.
O rută cu un parametru de cale
Același do_GET trimite /users într-o ramură și /users/7 în alta — o singură împărțire, iar al doilea segment aduce valoarea 7.
Ieșire: program Python complet
import threading
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class UsersHandler(BaseHTTPRequestHandler):
def do_GET(self):
parts = self.path.strip("/").split("/") # "/users/7" -> ["users", "7"]
if parts == ["users"]:
self.reply("toți utilizatorii: Ana, Ben, Cleo\n")
elif len(parts) == 2 and parts[0] == "users":
user_id = parts[1] # parametrul de cale
self.reply(f"un utilizator, id = {user_id}\n")
else:
self.reply("nimic aici\n", status=404)
def reply(self, text, status=200):
self.send_response(status)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(text.encode())
def log_message(self, fmt, *args):
pass
server = ThreadingHTTPServer(("127.0.0.1", 0), UsersHandler)
port = server.server_address[1]
threading.Thread(target=server.serve_forever, daemon=True).start()
for path in ["/users", "/users/7"]:
with urllib.request.urlopen(f"http://127.0.0.1:{port}{path}") as resp:
print("GET", path, "->", resp.read().decode(), end="")
server.shutdown()
Parametri de interogare
Partea de după ? conține parametrii de interogare — opțiuni pentru cerere, cum ar fi un text de căutare sau o limită: /search?q=python&limit=2. urlparse îi separă de cale, iar parse_qs îi transformă într-un dicționar de liste — mereu șiruri, iar .get acoperă parametrii lipsă.
Regula de bază: calea spune care resursă, interogarea spune cum — filtre, sortare, paginare.
Citirea șirului de interogare
Handlerul citește q și limit din interogare. A doua cerere omite limit, așa că handlerul folosește o valoare implicită — parametrii lipsă sunt ceva normal, pregătește-te pentru ei.
Ieșire: program Python complet
import threading
import urllib.request
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse
class SearchHandler(BaseHTTPRequestHandler):
def do_GET(self):
url = urlparse(self.path) # separă calea de interogare
params = parse_qs(url.query) # {"q": ["python"], ...}
q = params.get("q", [""])[0]
limit = params.get("limit", ["10"])[0] # valoare implicită pentru cei lipsă
body = f"căutare: {q}, limită: {limit}\n"
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(body.encode())
def log_message(self, fmt, *args):
pass
server = ThreadingHTTPServer(("127.0.0.1", 0), SearchHandler)
port = server.server_address[1]
threading.Thread(target=server.serve_forever, daemon=True).start()
for path in ["/search?q=python&limit=2", "/search?q=json"]:
with urllib.request.urlopen(f"http://127.0.0.1:{port}{path}") as resp:
print("GET", path, "->", resp.read().decode(), end="")
server.shutdown()