从零开始编写一个完整的Python HTTP REST API服务

不使用任何外部Web框架(如Flask/Django/FastAPI),仅使用Python标准库。

这是一个功能完整的实现,包含路由、中间件、JSON处理、错误处理等核心功能:

python 复制代码
#!/usr/bin/env python3
"""
从零开始的Python HTTP REST API服务
使用标准库实现,不依赖Flask/Django/FastAPI等框架
"""

import json
import socket
import threading
import urllib.parse
from http.server import HTTPServer, BaseHTTPRequestHandler
from typing import Dict, Callable, Any, Optional, List, Tuple
import re
from datetime import datetime


# ==================== 核心路由系统 ====================

class Route:
    """路由定义类"""
    def __init__(self, path: str, methods: List[str], handler: Callable):
        self.path = path
        self.methods = [m.upper() for m in methods]
        self.handler = handler
        # 将路径转换为正则表达式,支持动态参数如 /users/<id>
        self.pattern = self._compile_pattern(path)
    
    def _compile_pattern(self, path: str) -> re.Pattern:
        """将路径编译为正则表达式"""
        # 将 <param> 转换为命名捕获组
        pattern = re.sub(r'<(\w+)>', r'(?P<\1>[^/]+)', path)
        pattern = f'^{pattern}$'
        return re.compile(pattern)
    
    def match(self, path: str, method: str) -> Tuple[bool, Optional[Dict[str, str]]]:
        """匹配路径和方法"""
        if method.upper() not in self.methods:
            return False, None
        
        match = self.pattern.match(path)
        if match:
            return True, match.groupdict()
        return False, None


class Router:
    """路由器 - 管理所有路由"""
    def __init__(self):
        self.routes: List[Route] = []
        self.middlewares: List[Callable] = []
    
    def add_route(self, path: str, methods: List[str], handler: Callable):
        """添加路由"""
        route = Route(path, methods, handler)
        self.routes.append(route)
        return handler  # 支持装饰器用法
    
    def get(self, path: str):
        """GET请求装饰器"""
        def decorator(handler: Callable):
            return self.add_route(path, ['GET'], handler)
        return decorator
    
    def post(self, path: str):
        """POST请求装饰器"""
        def decorator(handler: Callable):
            return self.add_route(path, ['POST'], handler)
        return decorator
    
    def put(self, path: str):
        """PUT请求装饰器"""
        def decorator(handler: Callable):
            return self.add_route(path, ['PUT'], handler)
        return decorator
    
    def delete(self, path: str):
        """DELETE请求装饰器"""
        def decorator(handler: Callable):
            return self.add_route(path, ['DELETE'], handler)
        return decorator
    
    def patch(self, path: str):
        """PATCH请求装饰器"""
        def decorator(handler: Callable):
            return self.add_route(path, ['PATCH'], handler)
        return decorator
    
    def add_middleware(self, middleware: Callable):
        """添加中间件"""
        self.middlewares.append(middleware)
    
    def find_handler(self, path: str, method: str) -> Tuple[Optional[Callable], Optional[Dict[str, str]]]:
        """查找匹配的路由处理器"""
        for route in self.routes:
            matched, params = route.match(path, method)
            if matched:
                return route.handler, params
        return None, None


# ==================== 请求和响应对象 ====================

class Request:
    """HTTP请求对象"""
    def __init__(self, handler: BaseHTTPRequestHandler):
        self.handler = handler
        self.method = handler.command
        self.path = handler.path
        self.headers = dict(handler.headers)
        self.query_params = self._parse_query()
        self.body = self._parse_body()
        self.path_params: Dict[str, str] = {}
        self.context: Dict[str, Any] = {}  # 中间件可存储数据
    
    def _parse_query(self) -> Dict[str, List[str]]:
        """解析URL查询参数"""
        parsed = urllib.parse.urlparse(self.path)
        return urllib.parse.parse_qs(parsed.query)
    
    def _parse_body(self) -> Any:
        """解析请求体"""
        content_length = self.headers.get('Content-Length')
        if not content_length:
            return None
        
        try:
            length = int(content_length)
            body = self.handler.rfile.read(length).decode('utf-8')
            
            # 尝试解析JSON
            content_type = self.headers.get('Content-Type', '')
            if 'application/json' in content_type:
                return json.loads(body)
            return body
        except (ValueError, json.JSONDecodeError):
            return None
    
    def get_query(self, key: str, default: Any = None) -> Any:
        """获取查询参数"""
        values = self.query_params.get(key)
        return values[0] if values else default
    
    def get_header(self, key: str, default: str = None) -> Optional[str]:
        """获取请求头"""
        return self.headers.get(key, default)


class Response:
    """HTTP响应对象"""
    def __init__(self):
        self.status_code = 200
        self.headers: Dict[str, str] = {
            'Content-Type': 'application/json'
        }
        self.body: Any = None
    
    def set_status(self, code: int):
        """设置状态码"""
        self.status_code = code
        return self
    
    def set_header(self, key: str, value: str):
        """设置响应头"""
        self.headers[key] = value
        return self
    
    def json(self, data: Any):
        """设置JSON响应体"""
        self.body = json.dumps(data, ensure_ascii=False, indent=2)
        self.headers['Content-Type'] = 'application/json; charset=utf-8'
        return self
    
    def text(self, text: str):
        """设置文本响应体"""
        self.body = text
        self.headers['Content-Type'] = 'text/plain; charset=utf-8'
        return self
    
    def html(self, html: str):
        """设置HTML响应体"""
        self.body = html
        self.headers['Content-Type'] = 'text/html; charset=utf-8'
        return self


# ==================== 错误处理 ====================

class APIError(Exception):
    """API错误异常"""
    def __init__(self, message: str, status_code: int = 400, details: Any = None):
        self.message = message
        self.status_code = status_code
        self.details = details
        super().__init__(self.message)


# ==================== 数据库模拟(内存存储)====================

class Database:
    """模拟数据库 - 使用内存存储"""
    def __init__(self):
        self._data: Dict[str, List[Dict]] = {}
        self._id_counters: Dict[str, int] = {}
    
    def get_table(self, table_name: str) -> List[Dict]:
        """获取表数据"""
        return self._data.setdefault(table_name, [])
    
    def next_id(self, table_name: str) -> int:
        """生成自增ID"""
        self._id_counters[table_name] = self._id_counters.get(table_name, 0) + 1
        return self._id_counters[table_name]
    
    def find_all(self, table_name: str) -> List[Dict]:
        """查询所有记录"""
        return list(self.get_table(table_name))
    
    def find_by_id(self, table_name: str, id: int) -> Optional[Dict]:
        """根据ID查询"""
        table = self.get_table(table_name)
        for item in table:
            if item.get('id') == id:
                return item
        return None
    
    def create(self, table_name: str, data: Dict) -> Dict:
        """创建记录"""
        table = self.get_table(table_name)
        new_item = {
            'id': self.next_id(table_name),
            'created_at': datetime.now().isoformat(),
            **data
        }
        table.append(new_item)
        return new_item
    
    def update(self, table_name: str, id: int, data: Dict) -> Optional[Dict]:
        """更新记录"""
        item = self.find_by_id(table_name, id)
        if item:
            item.update({
                'updated_at': datetime.now().isoformat(),
                **data
            })
        return item
    
    def delete(self, table_name: str, id: int) -> bool:
        """删除记录"""
        table = self.get_table(table_name)
        for i, item in enumerate(table):
            if item.get('id') == id:
                table.pop(i)
                return True
        return False


# 全局数据库实例
db = Database()


# ==================== HTTP请求处理器 ====================

class APIHandler(BaseHTTPRequestHandler):
    """自定义HTTP请求处理器"""
    router: Router = None
    
    def log_message(self, format, *args):
        """自定义日志"""
        print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {self.address_string()} - {format % args}")
    
    def _send_response(self, response: Response):
        """发送HTTP响应"""
        self.send_response(response.status_code)
        for key, value in response.headers.items():
            self.send_header(key, value)
        self.end_headers()
        
        if response.body:
            if isinstance(response.body, str):
                self.wfile.write(response.body.encode('utf-8'))
            else:
                self.wfile.write(response.body)
    
    def _handle_error(self, error: APIError):
        """处理API错误"""
        response = Response().set_status(error.status_code).json({
            'error': error.message,
            'details': error.details,
            'timestamp': datetime.now().isoformat()
        })
        self._send_response(response)
    
    def _handle_exception(self, exc: Exception):
        """处理未捕获异常"""
        response = Response().set_status(500).json({
            'error': 'Internal Server Error',
            'message': str(exc),
            'timestamp': datetime.now().isoformat()
        })
        self._send_response(response)
    
    def _process_request(self, method: str):
        """处理请求"""
        try:
            # 创建请求对象
            request = Request(self)
            
            # 解析路径(去掉查询字符串)
            parsed_path = urllib.parse.urlparse(request.path).path
            
            # 查找路由处理器
            handler, path_params = self.router.find_handler(parsed_path, method)
            
            if not handler:
                raise APIError(f"Route not found: {request.method} {parsed_path}", 404)
            
            request.path_params = path_params or {}
            
            # 执行中间件(简化版,实际可链式调用)
            for middleware in self.router.middlewares:
                middleware(request)
            
            # 调用处理器
            response = handler(request)
            
            if not isinstance(response, Response):
                # 如果返回的是字典或列表,自动包装为JSON
                response = Response().json(response)
            
            self._send_response(response)
            
        except APIError as e:
            self._handle_error(e)
        except Exception as e:
            self._handle_exception(e)
    
    def do_GET(self):
        self._process_request('GET')
    
    def do_POST(self):
        self._process_request('POST')
    
    def do_PUT(self):
        self._process_request('PUT')
    
    def do_DELETE(self):
        self._process_request('DELETE')
    
    def do_PATCH(self):
        self._process_request('PATCH')
    
    def do_OPTIONS(self):
        """处理CORS预检请求"""
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
        self.end_headers()


# ==================== 应用类 ====================

class Application:
    """API应用主类"""
    def __init__(self):
        self.router = Router()
        APIHandler.router = self.router
    
    def get(self, path: str):
        return self.router.get(path)
    
    def post(self, path: str):
        return self.router.post(path)
    
    def put(self, path: str):
        return self.router.put(path)
    
    def delete(self, path: str):
        return self.router.delete(path)
    
    def patch(self, path: str):
        return self.router.patch(path)
    
    def use(self, middleware: Callable):
        """添加中间件"""
        self.router.add_middleware(middleware)
    
    def run(self, host: str = '0.0.0.0', port: int = 8000):
        """启动服务器"""
        server = HTTPServer((host, port), APIHandler)
        print(f"🚀 Server running at http://{host}:{port}/")
        print(f"📚 API Documentation: http://{host}:{port}/docs")
        print("Press Ctrl+C to stop...")
        
        try:
            server.serve_forever()
        except KeyboardInterrupt:
            print("\n👋 Server stopped.")


# ==================== 业务逻辑:用户管理API ====================

app = Application()


# 中间件:日志记录
@app.use
def logging_middleware(request: Request):
    """请求日志中间件"""
    print(f"→ {request.method} {request.path}")


# 中间件:认证模拟(演示用)
@app.use
def auth_middleware(request: Request):
    """认证中间件 - 演示用,实际应验证JWT等"""
    # 公开路径不需要认证
    public_paths = ['/docs', '/health', '/login']
    if any(request.path.startswith(p) for p in public_paths):
        return
    
    # 模拟认证检查
    auth_header = request.get_header('Authorization')
    request.context['user'] = {'id': 1, 'role': 'admin'}  # 模拟已登录用户


# ==================== API端点定义 ====================

@app.get('/')
def index(request: Request):
    """首页"""
    return {
        'message': 'Welcome to Python REST API',
        'version': '1.0.0',
        'docs': '/docs',
        'endpoints': {
            'users': '/api/users',
            'health': '/health'
        }
    }


@app.get('/health')
def health_check(request: Request):
    """健康检查"""
    return {
        'status': 'healthy',
        'timestamp': datetime.now().isoformat(),
        'database': 'connected'
    }


@app.get('/docs')
def api_docs(request: Request):
    """API文档"""
    html = """
    <!DOCTYPE html>
    <html>
    <head>
        <title>API Documentation</title>
        <style>
            body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
            h1 { color: #333; }
            .endpoint { background: #f4f4f4; padding: 15px; margin: 10px 0; border-radius: 5px; }
            .method { font-weight: bold; color: #fff; padding: 3px 8px; border-radius: 3px; display: inline-block; width: 60px; text-align: center; }
            .get { background: #4CAF50; }
            .post { background: #2196F3; }
            .put { background: #FF9800; }
            .delete { background: #f44336; }
            code { background: #e0e0e0; padding: 2px 5px; border-radius: 3px; }
        </style>
    </head>
    <body>
        <h1>🚀 REST API Documentation</h1>
        
        <h2>Users API</h2>
        
        <div class="endpoint">
            <span class="method get">GET</span>
            <code>/api/users</code>
            <p>获取所有用户</p>
            <p>Query: <code>?name=xxx</code> 按名称搜索</p>
        </div>
        
        <div class="endpoint">
            <span class="method get">GET</span>
            <code>/api/users/&lt;id&gt;</code>
            <p>获取单个用户</p>
        </div>
        
        <div class="endpoint">
            <span class="method post">POST</span>
            <code>/api/users</code>
            <p>创建用户</p>
            <p>Body: <code>{"name": "张三", "email": "zhangsan@example.com", "age": 25}</code></p>
        </div>
        
        <div class="endpoint">
            <span class="method put">PUT</span>
            <code>/api/users/&lt;id&gt;</code>
            <p>更新用户(全量更新)</p>
        </div>
        
        <div class="endpoint">
            <span class="method patch">PATCH</span>
            <code>/api/users/&lt;id&gt;</code>
            <p>部分更新用户</p>
        </div>
        
        <div class="endpoint">
            <span class="method delete">DELETE</span>
            <code>/api/users/&lt;id&gt;</code>
            <p>删除用户</p>
        </div>
        
        <h2>Other Endpoints</h2>
        <div class="endpoint">
            <span class="method get">GET</span>
            <code>/health</code> - 健康检查<br>
            <span class="method get">GET</span>
            <code>/</code> - API信息
        </div>
    </body>
    </html>
    """
    return Response().html(html)


# ==================== 用户CRUD API ====================

@app.get('/api/users')
def list_users(request: Request):
    """获取用户列表"""
    users = db.find_all('users')
    
    # 支持搜索
    search_name = request.get_query('name')
    if search_name:
        users = [u for u in users if search_name.lower() in u.get('name', '').lower()]
    
    # 支持分页
    page = int(request.get_query('page', 1))
    per_page = int(request.get_query('per_page', 10))
    start = (page - 1) * per_page
    end = start + per_page
    
    return {
        'data': users[start:end],
        'total': len(users),
        'page': page,
        'per_page': per_page,
        'total_pages': (len(users) + per_page - 1) // per_page
    }


@app.get('/api/users/<id>')
def get_user(request: Request):
    """获取单个用户"""
    user_id = int(request.path_params['id'])
    user = db.find_by_id('users', user_id)
    
    if not user:
        raise APIError(f"User with id {user_id} not found", 404)
    
    return {'data': user}


@app.post('/api/users')
def create_user(request: Request):
    """创建用户"""
    if not request.body:
        raise APIError("Request body required", 400)
    
    # 验证必填字段
    required = ['name', 'email']
    for field in required:
        if field not in request.body:
            raise APIError(f"Field '{field}' is required", 400)
    
    # 验证邮箱格式
    email = request.body['email']
    if '@' not in email:
        raise APIError("Invalid email format", 400)
    
    # 检查邮箱是否已存在
    existing = [u for u in db.find_all('users') if u.get('email') == email]
    if existing:
        raise APIError("Email already exists", 409)
    
    user = db.create('users', {
        'name': request.body['name'],
        'email': email,
        'age': request.body.get('age'),
        'phone': request.body.get('phone'),
        'address': request.body.get('address')
    })
    
    return Response().set_status(201).json({
        'message': 'User created successfully',
        'data': user
    })


@app.put('/api/users/<id>')
def update_user(request: Request):
    """全量更新用户"""
    user_id = int(request.path_params['id'])
    
    if not request.body:
        raise APIError("Request body required", 400)
    
    # 验证必填字段
    required = ['name', 'email']
    for field in required:
        if field not in request.body:
            raise APIError(f"Field '{field}' is required for PUT", 400)
    
    updated = db.update('users', user_id, {
        'name': request.body['name'],
        'email': request.body['email'],
        'age': request.body.get('age'),
        'phone': request.body.get('phone'),
        'address': request.body.get('address')
    })
    
    if not updated:
        raise APIError(f"User with id {user_id} not found", 404)
    
    return {
        'message': 'User updated successfully',
        'data': updated
    }


@app.patch('/api/users/<id>')
def patch_user(request: Request):
    """部分更新用户"""
    user_id = int(request.path_params['id'])
    
    if not request.body:
        raise APIError("Request body required", 400)
    
    # 只允许更新特定字段
    allowed_fields = ['name', 'email', 'age', 'phone', 'address']
    update_data = {k: v for k, v in request.body.items() if k in allowed_fields}
    
    if not update_data:
        raise APIError("No valid fields to update", 400)
    
    updated = db.update('users', user_id, update_data)
    
    if not updated:
        raise APIError(f"User with id {user_id} not found", 404)
    
    return {
        'message': 'User partially updated',
        'data': updated
    }


@app.delete('/api/users/<id>')
def delete_user(request: Request):
    """删除用户"""
    user_id = int(request.path_params['id'])
    
    success = db.delete('users', user_id)
    if not success:
        raise APIError(f"User with id {user_id} not found", 404)
    
    return Response().set_status(204).json({
        'message': 'User deleted successfully'
    })


# ==================== 启动服务器 ====================

if __name__ == '__main__':
    # 预置一些测试数据
    db.create('users', {
        'name': '张三',
        'email': 'zhangsan@example.com',
        'age': 28,
        'phone': '13800138001'
    })
    db.create('users', {
        'name': '李四',
        'email': 'lisi@example.com',
        'age': 32,
        'phone': '13800138002'
    })
    db.create('users', {
        'name': '王五',
        'email': 'wangwu@example.com',
        'age': 25,
        'phone': '13800138003'
    })
    
    print("📝 Test data created: 3 users")
    
    # 启动服务器
    app.run(host='0.0.0.0', port=8000)

功能特性

特性 说明 零依赖 仅使用Python标准库(http.server, socket, json, re等) RESTful路由 支持动态参数 /users/<id>,自动解析 完整CRUD 创建、读取、更新、删除(PUT/PATCH区分) 中间件系统 支持日志、认证等中间件链 错误处理 统一的API异常处理,返回标准JSON错误 请求/响应对象 封装Query参数、Body解析、Header操作 内存数据库 模拟数据库操作,支持搜索和分页 自动文档 内置HTML API文档页面 CORS支持 处理跨域预检请求

快速测试

启动服务器后,使用curl测试:

bash 复制代码
# 启动服务器
python api_server.py

# 查看API文档
open http://localhost:8000/docs

# 获取所有用户
curl http://localhost:8000/api/users

# 创建用户
curl -X POST http://localhost:8000/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"赵六","email":"zhaoliu@example.com","age":30}'

# 获取单个用户
curl http://localhost:8000/api/users/1

# 更新用户
curl -X PUT http://localhost:8000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"张三(已修改)","email":"zhangsan@example.com","age":29}'

# 部分更新
curl -X PATCH http://localhost:8000/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"age":30}'

# 删除用户
curl -X DELETE http://localhost:8000/api/users/1

# 搜索用户
curl "http://localhost:8000/api/users?name=张"

# 分页
curl "http://localhost:8000/api/users?page=1&per_page=2"

这个实现展示了HTTP服务器的核心原理,适合学习理解Web框架底层机制。生产环境建议使用FastAPI或Flask等专业框架。

相关推荐
清水白石00810 小时前
突破并行瓶颈:Python 多进程开销全解析与 IPC 优化实战
开发语言·网络·python
Lupino11 小时前
IoT 平台可编程化:基于 Pydantic Monty 构建工业级智能自动化链路
python
清水白石00812 小时前
突破性能瓶颈:深度解析 Numba 如何让 Python 飙到 C 语言的速度
开发语言·python
yunhuibin13 小时前
AlexNet网络学习
人工智能·python·深度学习·神经网络
喵手14 小时前
Python爬虫实战:增量爬虫实战 - 利用 HTTP 缓存机制实现“极致减负”(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·增量爬虫·http缓存机制·极致减负
一个处女座的程序猿O(∩_∩)O15 小时前
Python异常处理完全指南:KeyError、TypeError、ValueError深度解析
开发语言·python
was17215 小时前
使用 Python 脚本一键上传图片到兰空图床并自动复制链接
python·api上传·自建图床·一键脚本
好学且牛逼的马15 小时前
从“Oak”到“虚拟线程”:JDK 1.0到25演进全记录与核心知识点详解a
java·开发语言·python
shangjian00715 小时前
Python基础-环境安装-Anaconda配置虚拟环境
开发语言·python