1. 什么是 Starlette? #
Starlette 是一个用来写 Web 接口的 Python 框架。你可以用它定义路由(如 /hello)、处理 HTTP 请求、返回 JSON 或 HTML 等响应。它轻量、支持异步,是 FastAPI 的底层框架。
为什么学 Starlette?
- 想用 Python 写 Web API,又不想用 FastAPI 那么「重」的框架
- 需要理解 FastAPI 的底层原理
- 喜欢自己组合组件、控制细节
2. 前置知识 #
Web 框架与路由
- Web 框架:帮你处理 HTTP 请求、组织代码、返回响应的工具库
- 路由:把「URL 路径 + 请求方法」映射到具体的处理函数,例如
/hello→hello_handler
ASGI 是什么?
- ASGI 是 Python 异步 Web 应用的接口规范
- Starlette 是 ASGI 框架,必须通过 uvicorn 等 ASGI 服务器运行
- 可以理解为:Starlette 写应用,uvicorn 负责接收请求并调用你的应用
异步(async/await)
- Starlette 的路由处理函数通常是
async def - 在异步函数里可以
await其他异步操作(如读数据库、调接口),不会阻塞整个程序
3. 安装 #
在命令行中执行:
pip install starlette uvicornstarlette:Web 框架uvicorn:用来运行 Starlette 的 ASGI 服务器
如需解析表单数据(如 application/x-www-form-urlencoded),可额外安装:
pip install python-multipart4. 第一个应用 #
下面是一个完整的 Starlette 应用,定义了一个根路径 /,返回 JSON。
步骤 1:新建 app.py,写入:
# 导入 Starlette 应用类、路由、JSON 响应
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
# 处理根路径 / 的请求,接收 request 参数
async def homepage(request):
# 返回 JSON 响应,自动设置 Content-Type 为 application/json
return JSONResponse({"message": "Hello, Starlette!"})
# 定义路由列表:路径 / 对应 homepage 函数
routes = [
Route("/", endpoint=homepage),
]
# 创建 Starlette 应用,传入路由
app = Starlette(routes=routes)步骤 2:在终端执行:
uvicorn app:app步骤 3:浏览器访问 http://127.0.0.1:8000,会看到 {"message":"Hello, Starlette!"}。
5. 用装饰器定义路由 #
除了用 Route 列表,也可以用装饰器 `@app.route()` 添加路由,写法更简洁。
# 导入 Starlette 和 JSONResponse
from starlette.applications import Starlette
from starlette.responses import JSONResponse
# 先创建应用(此时没有路由)
app = Starlette()
# 用装饰器把路径 / 绑定到 homepage 函数
@app.route("/")
async def homepage(request):
return JSONResponse({"message": "Hello, World!"})注意:装饰器方式需要先 app = Starlette(),再写 `@app.route()`。两种方式可以混用。
6. 请求对象(request)常用属性 #
路由处理函数会收到一个 request 参数,通过它可以获取请求信息。
| 属性/方法 | 说明 |
|---|---|
request.method |
HTTP 方法,如 GET、POST |
request.url |
请求的完整 URL |
request.headers |
请求头(类似字典) |
request.query_params |
查询参数,如 ?name=张三 |
request.path_params |
路径参数,如 /user/123 中的 123 |
await request.json() |
解析 JSON 请求体 |
await request.body() |
原始请求体(bytes) |
7. 路径参数 #
路径参数是 URL 中的变量,例如 /user/张三 中的 张三。用 {name} 定义,在 request.path_params 中获取。
# 导入 Starlette 和 JSONResponse
from starlette.applications import Starlette
from starlette.responses import JSONResponse
app = Starlette()
# 根路径
@app.route("/")
async def index(request):
return JSONResponse({"message": "欢迎"})
# 路径 /hello/xxx,xxx 会存入 path_params["name"]
@app.route("/hello/{name}")
async def greet(request):
# 从路径参数中取出 name
name = request.path_params["name"]
return JSONResponse({"greeting": f"你好, {name}!"})
# 路径 /user/{user_id}/post/{post_id},多个路径参数
@app.route("/user/{user_id}/post/{post_id}")
async def user_post(request):
user_id = request.path_params["user_id"]
post_id = request.path_params["post_id"]
return JSONResponse({"user_id": user_id, "post_id": post_id})运行:uvicorn app:app,然后访问 http://127.0.0.1:8000/hello/张三。
8. 查询参数与请求体 #
查询参数:URL 中 ? 后面的部分,如 ?page=1&size=10。
请求体:POST 等请求携带的数据,常见格式为 JSON。
# 导入 Starlette 和 JSONResponse
from starlette.applications import Starlette
from starlette.responses import JSONResponse
app = Starlette()
# 获取查询参数,例如 /search?q=python&page=1
@app.route("/search")
async def search(request):
# query_params 类似字典,支持 .get() 避免 KeyError
q = request.query_params.get("q", "")
page = request.query_params.get("page", "1")
return JSONResponse({"q": q, "page": page})
# 接收 JSON 请求体,例如 POST /api/user,body: {"name":"小明","age":18}
@app.route("/api/user", methods=["POST"])
async def create_user(request):
# 解析 JSON 请求体为字典
data = await request.json()
name = data.get("name", "")
age = data.get("age", 0)
return JSONResponse({"created": True, "name": name, "age": age})注意:methods=["POST"] 表示只接受 POST 请求,不写则默认接受所有方法。
9. 常用响应类型 #
Starlette 提供多种响应类,常用如下:
| 类 | 说明 |
|---|---|
JSONResponse |
返回 JSON |
HTMLResponse |
返回 HTML |
PlainTextResponse |
返回纯文本 |
Response |
通用响应,可自定义状态码、头部 |
# 导入多种响应类型
from starlette.applications import Starlette
from starlette.responses import JSONResponse, HTMLResponse, PlainTextResponse, Response
app = Starlette()
# 返回 JSON
@app.route("/json")
async def json_view(request):
return JSONResponse({"key": "value"})
# 返回 HTML
@app.route("/html")
async def html_view(request):
return HTMLResponse("<h1>Hello</h1><p>这是 HTML</p>")
# 返回纯文本
@app.route("/text")
async def text_view(request):
return PlainTextResponse("纯文本内容")
# 自定义状态码和响应头
@app.route("/custom")
async def custom_view(request):
return Response(
content="自定义响应",
status_code=201,
headers={"X-Custom": "my-header"},
)10. 添加 CORS 中间件 #
当前端(如浏览器中的 JavaScript)请求你的 API 时,浏览器会做「跨域」检查。若接口未设置 CORS,可能被浏览器拦截。通过 CORS 中间件可以允许指定来源的跨域请求。
# 导入 Starlette、路由、响应、中间件
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
async def api_handler(request):
return JSONResponse({"data": "ok"})
# 路由列表
routes = [
Route("/api", endpoint=api_handler),
]
# 中间件列表:允许所有来源(开发时常用,生产环境建议指定具体域名)
middleware = [
Middleware(CORSMiddleware, allow_origins=["*"]),
]
# 创建应用时传入 middleware,注意顺序:后添加的先执行
app = Starlette(routes=routes, middleware=middleware)11. 可独立运行的项目 #
下面是一个包含多个路由、路径参数、查询参数、JSON 请求体和 CORS 的项目。
文件:demo_app.py
# 导入 Starlette 相关组件
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route
from starlette.middleware import Middleware
from starlette.middleware.cors import CORSMiddleware
# 根路径
async def index(request):
return JSONResponse({"message": "Starlette 入门示例", "docs": "/hello/{name}, /search?q=xxx, POST /api/echo"})
# 路径参数示例
async def greet(request):
name = request.path_params.get("name", "访客")
return JSONResponse({"greeting": f"你好, {name}!"})
# 查询参数示例
async def search(request):
q = request.query_params.get("q", "")
return JSONResponse({"query": q, "results": []})
# POST JSON 示例
async def echo(request):
data = await request.json()
return JSONResponse({"echo": data})
# 路由定义
routes = [
Route("/", endpoint=index),
Route("/hello/{name}", endpoint=greet),
Route("/search", endpoint=search),
Route("/api/echo", endpoint=echo, methods=["POST"]),
]
# CORS 中间件
middleware = [
Middleware(CORSMiddleware, allow_origins=["*"]),
]
# 创建应用
app = Starlette(routes=routes, middleware=middleware)运行:uvicorn demo_app:app --reload
测试:
- GET
http://127.0.0.1:8000/ - GET
http://127.0.0.1:8000/hello/张三 - GET
http://127.0.0.1:8000/search?q=python - POST
http://127.0.0.1:8000/api/echo,Body 选 JSON:{"test": 123}
12. 与 FastAPI 的关系 #
FastAPI 基于 Starlette 构建,在 Starlette 之上增加了:
- 基于类型提示的请求验证(Pydantic)
- 自动生成 API 文档(Swagger、ReDoc)
- 更丰富的依赖注入
如何选择?
- 需要自动文档、强类型验证 → 用 FastAPI
- 需要轻量、自己控制细节、写中间件或底层工具 → 用 Starlette
13. 常见问题 #
13.1 如何只允许 POST 请求? #
在 Route 中指定 methods:
# 导入路由和响应
from starlette.routing import Route
from starlette.responses import JSONResponse
# 只接受 POST
Route("/submit", endpoint=submit_handler, methods=["POST"])13.2 如何返回 404 或 500? #
使用 HTTPException 或自定义 Response 的状态码:
# 导入 HTTPException
from starlette.exceptions import HTTPException
@app.route("/notfound")
async def notfound(request):
# 抛出 404,Starlette 会转换为响应
raise HTTPException(status_code=404, detail="未找到")13.3 如何获取请求头? #
通过 request.headers,类似字典:
# 获取 User-Agent
user_agent = request.headers.get("user-agent", "")
# 获取 Authorization
auth = request.headers.get("authorization", "")14. 总结 #
- Starlette 是轻量级 ASGI 框架,适合写 Web API
- 用
Route或 `@app.route()定义路由,处理函数为async def xxx(request)` - 通过
request.path_params、request.query_params、await request.json()获取请求数据 - 用
JSONResponse、HTMLResponse等返回响应 - 用
Middleware(CORSMiddleware, ...)处理跨域 - 通过
uvicorn app:app运行应用