← Назад к вопросам

Что делать, если нет веб-фреймворков?

2.4 Senior🔥 141 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разработка веб-приложений без фреймворков

Это отличный вопрос, который проверяет глубину понимания того, как работают веб-приложения. Даже без фреймворков, Python предоставляет встроенные инструменты для создания веб-серверов.

Почему это может быть нужно

  • Образовательные цели (понимание основ HTTP, WSGI)
  • Специфические требования (минимальные зависимости)
  • Встроенные системы с ограничениями
  • Критичная производительность и контроль

Вариант 1: http.server (встроенный модуль)

from http.server import HTTPServer, BaseHTTPRequestHandler
import json
from urllib.parse import urlparse, parse_qs

class SimpleAPIHandler(BaseHTTPRequestHandler):
    """Простой обработчик HTTP запросов"""
    
    def do_GET(self):
        """Обработка GET запросов"""
        path = urlparse(self.path).path
        
        if path == "/":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"message": "Welcome to simple API"}
            self.wfile.write(json.dumps(response).encode())
        
        elif path.startswith("/users/"):
            user_id = path.split("/")[-1]
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"id": user_id, "name": "John", "email": "john@example.com"}
            self.wfile.write(json.dumps(response).encode())
        
        else:
            self.send_response(404)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"error": "Not found"}
            self.wfile.write(json.dumps(response).encode())
    
    def do_POST(self):
        """Обработка POST запросов"""
        content_length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(content_length)
        
        try:
            data = json.loads(body.decode())
            self.send_response(201)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"message": "Created", "data": data}
            self.wfile.write(json.dumps(response).encode())
        except json.JSONDecodeError:
            self.send_response(400)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            response = {"error": "Invalid JSON"}
            self.wfile.write(json.dumps(response).encode())
    
    def log_message(self, format, *args):
        """Подавить логирование по умолчанию"""
        pass

if __name__ == "__main__":
    server = HTTPServer(("localhost", 8000), SimpleAPIHandler)
    print("Server running on http://localhost:8000")
    server.serve_forever()

Запуск:

python simple_server.py
curl http://localhost:8000/
curl http://localhost:8000/users/1

Плюсы:

  • Нет зависимостей
  • Встроено в Python
  • Хорошо для образования

Минусы:

  • Однопоточный (обработка одного запроса за раз)
  • Не асинхронный
  • Нужно писать много кода для простых вещей

Вариант 2: socketserver с многопоточностью

from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ThreadingMixIn
import json
import threading

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """HTTP сервер с поддержкой многопоточности"""
    daemon_threads = True  # Потоки завершаются с основной программой

class RequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # Каждый запрос обрабатывается в отдельном потоке
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.end_headers()
        
        response = {
            "message": "Hello from thread",
            "thread": threading.current_thread().name
        }
        self.wfile.write(json.dumps(response).encode())

if __name__ == "__main__":
    server = ThreadedHTTPServer(("localhost", 8000), RequestHandler)
    print("Threaded server running")
    server.serve_forever()

Вариант 3: WSGI (Web Server Gateway Interface)

Применим стандарт WSGI, который используется всеми фреймворками:

from wsgiref.simple_server import make_server
import json
from urllib.parse import urlparse

def application(environ, start_response):
    """WSGI приложение"""
    path = environ.get("PATH_INFO", "/")
    method = environ.get("REQUEST_METHOD", "GET")
    
    if path == "/" and method == "GET":
        response_body = json.dumps({"message": "Welcome"})
        status = "200 OK"
        headers = [("Content-Type", "application/json")]
    
    elif path.startswith("/users/") and method == "GET":
        user_id = path.split("/")[-1]
        response_body = json.dumps({"id": user_id, "name": "John"})
        status = "200 OK"
        headers = [("Content-Type", "application/json")]
    
    else:
        response_body = json.dumps({"error": "Not found"})
        status = "404 Not Found"
        headers = [("Content-Type", "application/json")]
    
    # Отправить ответ
    start_response(status, headers)
    return [response_body.encode()]

if __name__ == "__main__":
    # WSGI сервер
    httpd = make_server("localhost", 8000, application)
    print("WSGI server running")
    httpd.serve_forever()

Плюсы WSGI:

  • Стандарт, поддерживаемый всеми серверами
  • Разделение приложения и сервера
  • Работает с gunicorn, uwsgi и др.

Вариант 4: Асинхронный сервер с asyncio

import asyncio
import json
from urllib.parse import urlparse

class SimpleAsyncServer:
    def __init__(self, host="localhost", port=8000):
        self.host = host
        self.port = port
    
    async def handle_client(self, reader, writer):
        """Обработать один клиента"""
        try:
            # Прочитать запрос
            request_line = await reader.readuntil(b"\r\n")
            request = request_line.decode().strip()
            
            # Парсинг запроса
            parts = request.split(" ")
            method = parts[0]
            path = parts[1]
            
            # Пропустить остальные заголовки
            while True:
                line = await reader.readuntil(b"\r\n")
                if line == b"\r\n":
                    break
            
            # Формировать ответ
            if path == "/":
                response_body = json.dumps({"message": "Async API"})
                status = "200 OK"
            else:
                response_body = json.dumps({"error": "Not found"})
                status = "404 Not Found"
            
            # Отправить HTTP ответ
            response = (
                f"HTTP/1.1 {status}\r\n"
                f"Content-Type: application/json\r\n"
                f"Content-Length: {len(response_body)}\r\n"
                f"\r\n"
                f"{response_body}"
            )
            
            writer.write(response.encode())
            await writer.drain()
        
        finally:
            writer.close()
            await writer.wait_closed()
    
    async def start(self):
        """Запустить сервер"""
        server = await asyncio.start_server(
            self.handle_client,
            self.host,
            self.port
        )
        
        print(f"Async server running on {self.host}:{self.port}")
        async with server:
            await server.serve_forever()

if __name__ == "__main__":
    server = SimpleAsyncServer()
    asyncio.run(server.start())

Сравнение подходов

ПодходПростотаПроизводительностьАсинхронностьКогда использовать
http.server⭐⭐⭐⭐⭐Обучение, прототипы
ThreadingMixIn⭐⭐⭐⭐⭐⭐Простые приложения
WSGI⭐⭐⭐⭐⭐⭐⭐Production apps
asyncio⭐⭐⭐⭐⭐⭐⭐High-load API

Реальный сценарий

В интервью я бы сказал:

"Если нет веб-фреймворков, я использую встроенные модули Python:

  1. Для прототипированияhttp.server со встроенным модулем
  2. Для простого веб-приложенияwsgiref с WSGI стандартом
  3. Для production — я бы всё равно установил фреймворк (Flask, FastAPI, Django), потому что они предоставляют:
    • Правильное разделение логики
    • Встроенные утилиты (роутинг, валидация)
    • Оптимизированную производительность
    • Экосистему плагинов

Но понимание основ HTTP, WSGI и асинхронного программирования — это критично для качественного разработчика."