1. Flask API开发入门指南
第一次接触Flask构建API时,我被它的简洁性惊艳到了。作为一个Python轻量级框架,Flask用不到10行代码就能搭建起一个可运行的Web服务端点。这种"微框架"的设计哲学特别适合快速原型开发和小型API项目。
在实际工作中,我经常用Flask为前端团队提供Mock API,或者快速搭建内部工具的后端接口。相比Django等全功能框架,Flask没有内置的ORM和Admin等组件,但正是这种"按需装配"的特性,让开发者可以灵活选择扩展库,构建最适合当前项目的技术栈。
2. 环境准备与基础配置
2.1 开发环境搭建
建议使用Python 3.7+版本,这是目前大多数生产环境采用的稳定版本。我习惯使用virtualenv创建隔离环境:
bash复制python -m venv flask_env
source flask_env/bin/activate # Linux/Mac
flask_env\Scripts\activate # Windows
安装核心依赖时,除了Flask本身,我还会带上几个常用扩展:
bash复制pip install flask flask-restful flask-cors
注意:生产环境建议固定依赖版本,可以使用
pip freeze > requirements.txt生成依赖清单
2.2 最小化API示例
创建一个app.py文件,写入以下代码:
python复制from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/hello', methods=['GET'])
def hello():
return jsonify({"message": "Hello, Flask API!"})
if __name__ == '__main__':
app.run(debug=True)
运行这个服务:
bash复制python app.py
访问http://127.0.0.1:5000/api/hello就能看到JSON格式的响应。这个简单示例展示了Flask API的三个核心要素:
- 应用实例创建 (
Flask(__name__)) - 路由装饰器定义端点 (
@app.route) - 视图函数处理请求并返回响应
3. 进阶API开发技巧
3.1 请求数据处理
实际API开发中,我们需要处理各种HTTP方法和请求数据。Flask提供了方便的请求对象:
python复制from flask import request
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json() # 自动解析JSON body
if not data or 'username' not in data:
return jsonify({"error": "Bad request"}), 400
# 处理业务逻辑
new_user = {
"id": 1,
"username": data['username']
}
return jsonify(new_user), 201
对于表单数据,可以使用request.form;文件上传则用request.files。我建议始终明确指定methods参数,避免意外的HTTP方法调用。
3.2 响应标准化
保持API响应格式一致很重要。我通常会创建一个响应工具函数:
python复制def api_response(data=None, message="", status=200):
return jsonify({
"data": data,
"message": message,
"status": status
}), status
这样在视图函数中可以统一调用:
python复制return api_response(new_user, "User created", 201)
3.3 错误处理
Flask允许注册全局错误处理器:
python复制@app.errorhandler(404)
def not_found(error):
return api_response(None, "Resource not found", 404)
@app.errorhandler(500)
def server_error(error):
return api_response(None, "Internal server error", 500)
对于业务逻辑错误,可以自定义异常类:
python复制class APIError(Exception):
def __init__(self, message, status=400):
super().__init__()
self.message = message
self.status = status
@app.errorhandler(APIError)
def handle_api_error(error):
return api_response(None, error.message, error.status)
4. 项目结构化与扩展
4.1 大型项目组织
当API规模增长时,建议采用模块化结构:
code复制/project
/app
/api
/v1 # API版本
__init__.py
users.py
products.py
__init__.py # 工厂函数
config.py
requirements.txt
使用工厂模式创建应用:
python复制# app/__init__.py
from flask import Flask
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
# 注册蓝图
from .api.v1 import api_bp
app.register_blueprint(api_bp, url_prefix='/api/v1')
return app
4.2 常用扩展推荐
-
Flask-RESTful:构建RESTful API的扩展
python复制from flask_restful import Api, Resource api = Api(app) class UserAPI(Resource): def get(self, user_id): return {"user": "data"} api.add_resource(UserAPI, '/users/<int:user_id>') -
Flask-CORS:处理跨域请求
python复制from flask_cors import CORS CORS(app) # 允许所有跨域请求 -
Flask-JWT-Extended:JWT认证
python复制from flask_jwt_extended import JWTManager, jwt_required app.config['JWT_SECRET_KEY'] = 'super-secret' jwt = JWTManager(app) @app.route('/protected') @jwt_required() def protected(): return {"message": "JWT验证通过"}
5. 性能优化与部署
5.1 生产环境配置
开发模式(debug=True)绝对不能用于生产。部署时需要调整配置:
python复制app.config.update(
DEBUG=False,
SECRET_KEY='your-production-secret',
JSONIFY_PRETTYPRINT_REGULAR=False # 禁用美化输出提升性能
)
建议使用Gunicorn作为WSGI服务器:
bash复制gunicorn -w 4 -b :8000 app:app
5.2 数据库集成
虽然Flask没有内置ORM,但Flask-SQLAlchemy是常用选择:
python复制from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
@app.route('/api/db-users')
def get_users():
users = User.query.all()
return api_response([u.username for u in users])
5.3 缓存策略
对于高频访问的API端点,可以考虑添加缓存:
python复制from flask_caching import Cache
cache = Cache(app, config={'CACHE_TYPE': 'simple'})
@app.route('/api/expensive')
@cache.cached(timeout=60)
def expensive_operation():
# 耗时计算
return api_response(result)
6. 测试与文档
6.1 单元测试
Flask提供了测试客户端:
python复制import unittest
from app import create_app
class APITestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.client = self.app.test_client()
def test_hello(self):
response = self.client.get('/api/hello')
self.assertEqual(response.status_code, 200)
self.assertIn(b'Hello', response.data)
6.2 API文档
使用Flask-Swagger或OpenAPI可以自动生成文档:
python复制from flasgger import Swagger
app.config['SWAGGER'] = {
'title': 'My API',
'version': '1.0'
}
swagger = Swagger(app)
@app.route('/api/hello')
def hello():
"""
A simple greeting endpoint
---
responses:
200:
description: A greeting message
"""
return jsonify({"message": "Hello"})
访问/apidocs即可查看交互式文档。
7. 实战经验分享
7.1 性能监控
在生产环境,我习惯添加性能监控:
python复制from werkzeug.middleware.profiler import ProfilerMiddleware
if app.config['PROFILE']:
app.wsgi_app = ProfilerMiddleware(
app.wsgi_app,
restrictions=[30],
profile_dir='./profiles'
)
7.2 请求验证
对于关键API,建议添加参数验证:
python复制from flask_expects_json import expects_json
schema = {
'type': 'object',
'properties': {
'username': {'type': 'string'},
'email': {'type': 'string', 'format': 'email'}
},
'required': ['username']
}
@app.route('/api/validate', methods=['POST'])
@expects_json(schema)
def validate():
return api_response(message="Validation passed")
7.3 异步任务
长时间操作应该异步处理:
python复制from flask import Flask
from celery import Celery
def make_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
return celery
app = Flask(__name__)
app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(app)
@celery.task
def async_task(data):
# 耗时处理
return result
@app.route('/api/async')
def trigger_async():
async_task.delay({"param": "value"})
return api_response(message="Task started")
8. 安全最佳实践
8.1 输入消毒
所有用户输入都应该被视为不可信的:
python复制from markupsafe import escape
@app.route('/api/search')
def search():
query = escape(request.args.get('q', ''))
# 使用消毒后的query进行搜索
8.2 速率限制
防止滥用API:
python复制from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.route('/api/limited')
@limiter.limit("10 per minute")
def limited():
return api_response(message="Rate limited endpoint")
8.3 HTTPS强制
生产环境必须使用HTTPS:
python复制@app.before_request
def enforce_https():
if not request.is_secure and not app.debug:
return redirect(request.url.replace('http://', 'https://'), code=301)
9. 微服务架构中的Flask API
9.1 服务发现
在微服务环境中,可以考虑使用Consul:
python复制import consul
c = consul.Consul()
def register_service():
c.agent.service.register(
'flask-api',
service_id='flask-api-1',
address='127.0.0.1',
port=5000,
check={
'http': 'http://127.0.0.1:5000/health',
'interval': '10s'
}
)
9.2 健康检查
每个API服务都应该提供健康端点:
python复制@app.route('/health')
def health():
return jsonify({"status": "healthy"}), 200
9.3 分布式追踪
集成Jaeger等分布式追踪系统:
python复制from jaeger_client import Config
def init_tracer(service):
config = Config(
config={
'sampler': {'type': 'const', 'param': 1},
'logging': True,
},
service_name=service,
)
return config.initialize_tracer()
tracer = init_tracer('flask-api')
@app.route('/api/traced')
def traced():
with tracer.start_span('traced-operation') as span:
span.log_kv({'event': 'processing'})
return api_response(message="Traced operation")
10. 持续集成与部署
10.1 自动化测试
.github/workflows/test.yml示例:
yaml复制name: Python Test
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.8'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
python -m pytest
10.2 Docker化部署
Dockerfile示例:
dockerfile复制FROM python:3.8-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
10.3 配置管理
使用环境变量管理配置:
python复制import os
from dotenv import load_dotenv
load_dotenv() # 从.env文件加载
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL')
11. 监控与日志
11.1 结构化日志
python复制import logging
from pythonjsonlogger import jsonlogger
def setup_logging():
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = jsonlogger.JsonFormatter(
'%(asctime)s %(levelname)s %(name)s %(message)s'
)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)
setup_logging()
@app.route('/api/log')
def log_example():
app.logger.info("API accessed", extra={
"endpoint": "/api/log",
"method": "GET"
})
return api_response(message="Logged")
11.2 性能指标
使用Prometheus客户端:
python复制from prometheus_client import make_wsgi_app, Counter
from werkzeug.middleware.dispatcher import DispatcherMiddleware
REQUESTS = Counter(
'flask_requests_total',
'Total request count',
['method', 'endpoint', 'http_status']
)
@app.after_request
def after_request(response):
REQUESTS.labels(
request.method,
request.path,
response.status_code
).inc()
return response
# 添加/metrics端点
app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
'/metrics': make_wsgi_app()
})
12. 版本控制策略
12.1 URL版本控制
python复制@app.route('/api/v2/hello')
def hello_v2():
return jsonify({
"message": "Hello from v2",
"features": ["new", "improved"]
})
12.2 内容协商版本控制
python复制from flask import request
@app.route('/api/hello')
def hello_negotiated():
version = request.headers.get('X-API-Version', '1')
if version == '2':
return jsonify({"message": "v2 response"})
else:
return jsonify({"message": "v1 response"})
12.3 蓝本版本控制
更推荐的方式是使用蓝本:
python复制from flask import Blueprint
v1_bp = Blueprint('v1', __name__)
v2_bp = Blueprint('v2', __name__)
@v1_bp.route('/hello')
def v1_hello():
return jsonify({"api": "v1"})
@v2_bp.route('/hello')
def v2_hello():
return jsonify({"api": "v2"})
app.register_blueprint(v1_bp, url_prefix='/api/v1')
app.register_blueprint(v2_bp, url_prefix='/api/v2')
13. 实战案例:用户管理系统API
13.1 数据模型设计
python复制from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
13.2 认证系统实现
python复制from flask_httpauth import HTTPBasicAuth
auth = HTTPBasicAuth()
@auth.verify_password
def verify_password(username, password):
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
return user
@app.route('/api/protected')
@auth.login_required
def protected():
return api_response(
data={"user": auth.current_user().username},
message="Authenticated"
)
13.3 完整CRUD实现
python复制from flask import abort
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
if 'username' not in data or 'password' not in data:
abort(400)
if User.query.filter_by(username=data['username']).first():
return api_response(None, "Username exists", 409)
user = User(username=data['username'], email=data.get('email'))
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
return api_response(
data={"id": user.id},
message="User created",
status=201
)
@app.route('/api/users/<int:id>', methods=['GET'])
def get_user(id):
user = User.query.get_or_404(id)
return api_response({
"username": user.username,
"email": user.email,
"created_at": user.created_at.isoformat()
})
# 类似实现update和delete端点
14. 性能优化进阶
14.1 数据库查询优化
python复制from sqlalchemy.orm import joinedload
@app.route('/api/users-with-posts')
def users_with_posts():
# 避免N+1查询问题
users = User.query.options(joinedload(User.posts)).all()
# ...
14.2 缓存策略优化
python复制from flask_caching import Cache
cache = Cache(config={
'CACHE_TYPE': 'redis',
'CACHE_REDIS_URL': 'redis://localhost:6379/0',
'CACHE_KEY_PREFIX': 'flask_api_'
})
def make_cache_key(*args, **kwargs):
path = request.path
args = str(hash(frozenset(request.args.items())))
return f"{path}:{args}"
@app.route('/api/expensive-query')
@cache.cached(timeout=300, key_prefix=make_cache_key)
def expensive_query():
# ...
14.3 异步任务处理
python复制@app.route('/api/long-task')
def start_long_task():
task = async_task.delay({"param": "value"})
return api_response(
data={"task_id": task.id},
message="Task started"
)
@app.route('/api/task-status/<task_id>')
def task_status(task_id):
task = async_task.AsyncResult(task_id)
return api_response({
"status": task.status,
"result": task.result if task.ready() else None
})
15. 测试策略全覆盖
15.1 单元测试示例
python复制class UserAPITestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.client = self.app.test_client()
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_user_creation(self):
response = self.client.post('/api/users', json={
'username': 'test',
'password': 'secret'
})
self.assertEqual(response.status_code, 201)
data = response.get_json()
self.assertIn('id', data['data'])
15.2 集成测试
python复制class AuthTestCase(unittest.TestCase):
def test_protected_access(self):
# 先创建测试用户
self.client.post('/api/users', json={
'username': 'test',
'password': 'secret'
})
# 测试认证访问
response = self.client.get(
'/api/protected',
headers={
'Authorization': 'Basic ' +
base64.b64encode(b'test:secret').decode('utf-8')
}
)
self.assertEqual(response.status_code, 200)
15.3 性能测试
使用Locust进行负载测试:
python复制from locust import HttpUser, task, between
class APIUser(HttpUser):
wait_time = between(1, 3)
@task
def get_hello(self):
self.client.get("/api/hello")
@task(3)
def create_user(self):
self.client.post("/api/users", json={
"username": "test",
"password": "secret"
})
16. 文档自动化
16.1 OpenAPI规范
python复制from flasgger import Swagger
template = {
"info": {
"title": "User API",
"description": "API for user management",
"version": "1.0"
},
"securityDefinitions": {
"basicAuth": {
"type": "basic"
}
}
}
swagger = Swagger(app, template=template)
@app.route('/api/users/<int:id>')
def get_user(id):
"""
Get user by ID
---
tags:
- users
parameters:
- name: id
in: path
type: integer
required: true
responses:
200:
description: User data
404:
description: User not found
"""
user = User.query.get_or_404(id)
return jsonify(user.to_dict())
16.2 交互式文档
访问/apidocs端点可以看到自动生成的Swagger UI界面,支持:
- 端点测试
- 模型查看
- 认证测试
17. 微服务通信
17.1 同步HTTP调用
python复制import requests
@app.route('/api/aggregate')
def aggregate_data():
user_service = os.getenv('USER_SERVICE_URL', 'http://user-service')
order_service = os.getenv('ORDER_SERVICE_URL', 'http://order-service')
try:
users = requests.get(f"{user_service}/users").json()
orders = requests.get(f"{order_service}/orders").json()
return api_response({
"user_count": len(users),
"order_count": len(orders)
})
except requests.exceptions.RequestException as e:
return api_response(None, str(e), 503)
17.2 异步消息队列
使用RabbitMQ进行异步通信:
python复制import pika
def publish_event(event_type, data):
connection = pika.BlockingConnection(
pika.ConnectionParameters('localhost')
)
channel = connection.channel()
channel.queue_declare(queue='events')
channel.basic_publish(
exchange='',
routing_key='events',
body=json.dumps({
'type': event_type,
'data': data
})
)
connection.close()
@app.route('/api/users', methods=['POST'])
def create_user():
# ... 用户创建逻辑
publish_event('user_created', {'user_id': user.id})
return api_response(...)
18. 配置管理进阶
18.1 多环境配置
config.py示例:
python复制import os
from dotenv import load_dotenv
load_dotenv()
class Config:
SECRET_KEY = os.getenv('SECRET_KEY')
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.getenv('DEV_DATABASE_URL')
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL')
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
18.2 敏感信息管理
使用Vault等工具管理密钥:
python复制import hvac
def get_secret(key):
client = hvac.Client(
url='http://vault:8200',
token=os.getenv('VAULT_TOKEN')
)
secret = client.secrets.kv.v2.read_secret_version(
path='flask-api',
mount_point='secret'
)
return secret['data']['data'][key]
19. 容器化部署进阶
19.1 Docker Compose编排
docker-compose.yml示例:
yaml复制version: '3'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- FLASK_ENV=production
- DATABASE_URL=postgresql://postgres:password@db/postgres
depends_on:
- db
- redis
db:
image: postgres:13
environment:
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:6
volumes:
postgres_data:
19.2 Kubernetes部署
deployment.yaml示例:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-api
spec:
replicas: 3
selector:
matchLabels:
app: flask-api
template:
metadata:
labels:
app: flask-api
spec:
containers:
- name: web
image: your-registry/flask-api:latest
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
20. 监控与告警
20.1 Prometheus监控
python复制from prometheus_client import start_http_server, Counter
REQUEST_COUNT = Counter(
'flask_requests_total',
'Total HTTP requests',
['method', 'endpoint', 'status']
)
@app.after_request
def after_request(response):
REQUEST_COUNT.labels(
request.method,
request.path,
response.status_code
).inc()
return response
# 在应用启动时
start_http_server(9000)
20.2 日志分析
使用ELK Stack收集分析日志:
python复制import logging
from logging.handlers import SysLogHandler
syslog = SysLogHandler(address=('logstash', 514))
syslog.setFormatter(logging.Formatter(
'%(asctime)s flask-api %(levelname)s %(message)s'
))
app.logger.addHandler(syslog)
20.3 性能剖析
使用Py-Spy进行性能分析:
bash复制py-spy top --pid $(pgrep -f "gunicorn: master")
21. 安全加固措施
21.1 依赖安全扫描
bash复制pip install safety
safety check
21.2 请求过滤
python复制from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
@app.before_request
def limit_remote_addr():
if request.remote_addr not in ['127.0.0.1', '192.168.1.0/24']:
abort(403)
21.3 CSRF保护
python复制from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
@app.route('/api/csrf-token')
def get_csrf_token():
return jsonify({'csrf_token': generate_csrf()})
22. 国际化支持
22.1 多语言API
python复制from flask_babel import Babel, _
babel = Babel(app)
@app.route('/api/hello')
def hello():
accept_language = request.headers.get('Accept-Language', 'en')
if 'zh' in accept_language:
return jsonify({"message": "你好"})
return jsonify({"message": "Hello"})
22.2 本地化错误消息
python复制class APIError(Exception):
def __init__(self, message_key, status=400, **kwargs):
self.message = _(message_key, **kwargs)
self.status = status
@app.errorhandler(APIError)
def handle_api_error(error):
return api_response(None, error.message, error.status)
23. GraphQL集成
23.1 Flask-GraphQL
python复制from flask_graphql import GraphQLView
from graphene import ObjectType, String, Schema
class Query(ObjectType):
hello = String(name=String(default_value="World"))
def resolve_hello(root, info, name):
return f'Hello {name}!'
schema = Schema(query=Query)
app.add_url_rule(
'/graphql',
view_func=GraphQLView.as_view(
'graphql',
schema=schema,
graphiql=True
)
)
23.2 与REST共存
python复制@app.route('/api/rest-hello')
def rest_hello():
return jsonify({"message": "This is REST"})
# GraphQL端点保持独立
24. WebSocket支持
24.1 Flask-SocketIO
python复制from flask_socketio import SocketIO, emit
socketio = SocketIO(app, cors_allowed_origins="*")
@socketio.on('connect')
def handle_connect():
print('Client connected')
@socketio.on('chat')
def handle_chat(data):
emit('message', {'text': data['text']}, broadcast=True)
if __name__ == '__main__':
socketio.run(app)
24.2 实时API通知
python复制@app.route('/api/notify', methods=['POST'])
def send_notification():
data = request.get_json()
socketio.emit('notification', data)
return api_response(message="Notification sent")
25. 机器学习集成
25.1 模型服务化
python复制import pickle
model = pickle.load(open('model.pkl', 'rb'))
@app.route('/api/predict', methods=['POST'])
def predict():
data = request.get_json()
features = preprocess(data)
prediction = model.predict([features])
return api_response({
"prediction": float(prediction[0])
})
25.2 异步预测
python复制@app.route('/api/async-predict', methods=['POST'])
def async_predict():
data = request.get_json()
task = predict_task.delay(data)
return api_response(
{"task_id": task.id},
message="Prediction started"
)
26. 无服务器部署
26.1 AWS Lambda部署
使用Zappa:
bash复制pip install zappa
zappa init
zappa deploy dev
26.2 Google Cloud Functions
main.py:
python复制from flask import Flask, request
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello from Cloud Function!'
def cloud_function(request):
with app.test_request_context(
path=request.path,
method=request.method,
headers=request.headers,
data=request.data
):
return app.full_dispatch_request()
27. 自动化文档生成
27.1 Sphinx文档
docs/conf.py:
python复制extensions = [
'sphinx.ext.autodoc',
'sphinxcontrib.httpdomain'
]
# 自动生成API文档
def run_apidoc(_):
from sphinx.ext.apidoc import main
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
cur_dir = os.path.abspath(os.path.dirname(__file__))
module = os.path.join(cur_dir, "..", "app")
main(['-e', '-o', cur_dir, module, '--force'])
def setup(app):
app.connect('builder-inited', run_apidoc)
27.2 交互式API控制台
使用ReDoc:
python复制@app.route('/docs')
def redoc():
return '''
<!DOCTYPE html>
<html>
<head>
<title>API Docs</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<style> body { margin: 0; padding: 0; } </style>
</head>
<body>
<redoc spec-url='/swagger.json'></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js"> </script>
</body>
</html>
'''
28. 持续交付流水线
28.1 GitHub Actions
.github/workflows/cd.yml:
yaml复制name: CD Pipeline
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
python -m pytest
- name: Build Docker image
run: |
docker build -t your-image .
- name: Deploy to Kubernetes
run: |
kubectl apply -f k8s/
28.2 自动化回滚
python复制@app.route('/api/deploy', methods=['POST'])
@auth.login_required
def deploy():
if not auth.current_user().is_admin:
abort(403)
try:
subprocess.run(['./deploy.sh'], check=True)
return api_response(message="Deployment started")
except subprocess.CalledProcessError:
subprocess.run(['./rollback.sh'])
return api_response(None, "Deployment failed", 500)
29. 边缘计算部署
29.1 轻量级部署
使用Waitress作为生产服务器:
python复制from waitress import serve
if __name__ == '__main__':
serve(app