不使用任何外部Web框架(如Flask/Django/FastAPI),仅使用Python标准库。
这是一个功能完整的实现,包含路由、中间件、JSON处理、错误处理等核心功能:
#!/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/<id></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/<id></code>
<p>更新用户(全量更新)</p>
</div>
<div class="endpoint">
<span class="method patch">PATCH</span>
<code>/api/users/<id></code>
<p>部分更新用户</p>
</div>
<div class="endpoint">
<span class="method delete">DELETE</span>
<code>/api/users/<id></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测试:
# 启动服务器
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等专业框架。