title: FastAPI 路径参数完全指南:从基础到高级校验实战 🚀
date: 2025/3/5
updated: 2025/3/5
author: cmdragon

excerpt:
探讨 FastAPI 路径参数的核心机制,涵盖从基础类型转换到高级校验的全方位知识。通过详细的代码示例、课后测验和常见错误解决方案,帮助初学者快速掌握 FastAPI 路径参数的使用技巧。您将学习到如何通过类型转换、正则表达式和自定义校验器来构建安全、高效的 API 接口。

categories:

  • 后端开发
  • FastAPI

tags:

  • FastAPI
  • 路径参数
  • 类型转换
  • 参数校验
  • 正则表达式
  • API安全
  • RESTful

image

image

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意

第一章:路径参数基础

1.1 什么是路径参数?

路径参数是 RESTful API 中用于标识资源的变量,通常出现在 URL 路径中。例如,/users/{user_id} 中的 user_id 就是一个路径参数。

from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"user_id": user_id}

1.2 类型转换

FastAPI 会自动将路径参数转换为指定的类型。如果转换失败,将返回 422 错误。

@app.get("/items/{item_id}")
async def get_item(item_id: int):
    return {"item_id": item_id}

示例请求

  • 合法:/items/123{"item_id": 123}
  • 非法:/items/abc → 422 错误

1.3 基础校验

使用 Pydantic 的 Fieldconint 等工具可以对路径参数进行基础校验。

from pydantic import conint


@app.get("/products/{product_id}")
async def get_product(product_id: conint(gt=1000)):
    return {"product_id": product_id}

示例请求

  • 合法:/products/1001{"product_id": 1001}
  • 非法:/products/999 → 422 错误

1.4 常见错误与解决方案

错误:422 Validation Error
原因:路径参数类型转换失败或校验不通过
解决方案:检查路径参数的类型定义和校验规则。


第二章:高级校验技巧

2.1 正则表达式校验

通过正则表达式可以对路径参数进行更复杂的格式校验。

from fastapi import Path


@app.get("/credit-cards/{card_no}")
async def get_card(card_no: str = Path(..., regex=r"^[4-6]\d{15}$")):
    return {"card_no": card_no}

示例请求

  • 合法:/credit-cards/4111111111111111{"card_no": "4111111111111111"}
  • 非法:/credit-cards/1234567812345678 → 422 错误

2.2 自定义验证器

通过 Pydantic 的自定义验证器,可以实现更复杂的校验逻辑。

from pydantic import BaseModel, validator


class ProductCode(str):
    @classmethod
    def validate(cls, value):
        if not re.match(r"^[A-Z]{3}-\d{3}[A-Z]$", value):
            raise ValueError("Invalid product code")
        return cls(value)


@app.get("/products/{code}")
async def get_product(code: ProductCode):
    return {"code": code}

示例请求

  • 合法:/products/ABC-123X{"code": "ABC-123X"}
  • 非法:/products/123-ABC → 422 错误

2.3 复合型校验

结合多种校验规则,可以实现更强大的参数验证。

from datetime import date


@app.get("/orders/{order_date}")
async def get_orders(order_date: date = Path(..., regex=r"^\d{4}-\d{2}-\d{2}$")):
    if order_date > date.today():
        raise HTTPException(400, "未来日期非法")
    return query_orders(order_date)

示例请求

  • 合法:/orders/2023-10-01 → 返回订单数据
  • 非法:/orders/2023-13-01 → 422 错误

2.4 常见错误与解决方案

错误:422 Validation Error
原因:正则表达式不匹配或自定义校验失败
解决方案:检查正则表达式模式和自定义校验逻辑。


第三章:安全最佳实践

3.1 SQL 注入防御

使用参数化查询可以有效防止 SQL 注入攻击。

# 危险示例
@app.get("/search/{keyword}")
async def unsafe_search(keyword: str):
    query = f"SELECT * FROM products WHERE name LIKE '%{keyword}%'"


# 安全方案
@app.get("/search/{keyword}")
async def safe_search(keyword: str):
    return await database.fetch_all(
        "SELECT * FROM products WHERE name LIKE :keyword",
        {"keyword": f"%{keyword}%"}
    )

Quiz:如何避免 SQL 注入攻击?
答案:使用参数化查询,避免直接拼接 SQL 语句。

3.2 路径遍历攻击防护

通过正则表达式限制路径参数,可以防止路径遍历攻击。

from pathlib import Path


@app.get("/files/{file_path:path}")
async def read_file(file_path: str = Path(..., regex=r"^[\w\-/]+$")):
    full_path = BASE_DIR / file_path
    if not full_path.resolve().startswith(BASE_DIR):
        raise HTTPException(403, "非法路径访问")
    return FileResponse(full_path)

示例请求

  • 合法:/files/document.txt → 返回文件内容
  • 非法:/files/../../etc/passwd → 403 错误

3.3 常见错误与解决方案

错误:403 Forbidden
原因:路径参数包含非法字符或路径遍历攻击
解决方案:检查路径参数的正则表达式和路径解析逻辑。


课后实战项目

项目 1:订单系统参数校验

@app.get("/orders/{order_id}")
async def get_order(order_id: str = Path(..., regex=r"^[A-Z]{2}\d{6}[A-Z0-9]{4}$")):
    return query_order(order_id)

任务:实现一个订单查询接口,确保订单号符合指定格式。

项目 2:地理坐标解析

@app.get("/coordinates/{coord}")
async def parse_coordinate(coord: str = Path(..., regex=r"^([-+]?\d+\.\d+),\s*([-+]?\d+\.\d+)$")):
    return parse_coord(coord)

任务:实现一个地理坐标解析接口,确保坐标格式正确。


错误代码应急手册

错误代码典型触发场景解决方案
422类型转换失败/正则不匹配检查参数定义的校验规则
404路径参数格式正确但资源不存在验证业务逻辑中的数据存在性
500未捕获的参数处理异常添加 try/except 包裹敏感操作
400自定义校验规则触发拒绝检查验证器的逻辑条件

常见问题解答

Q:路径参数能否使用枚举类型?
A:可以,使用 Enum 类实现:

from enum import Enum


class Color(str, Enum):
    RED = "red"
    BLUE = "blue"


@app.get("/colors/{color}")
async def get_color(color: Color):
    return {"color": color}

Q:如何处理带斜杠的路径参数?
A:使用 :path 参数类型声明:

@app.get("/files/{file_path:path}")
async def read_file(file_path: str):
    return {"file": file_path}

通过本教程的详细讲解和实战项目,您已掌握 FastAPI 路径参数的核心知识。现在可以通过以下命令测试您的学习成果:

curl -X GET "http://localhost:8000/credit-cards/4111111111111111"

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:FastAPI 路径参数完全指南:从基础到高级校验实战 🚀 | cmdragon's Blog

往期文章归档:


风流倜傥的伤痕
79 声望23 粉丝