FastAPI请求体参数解析:从基础到高级的学习

FastAPI 请求体参数详解

1. 参数类型

FastAPI 中的参数主要分为以下三种类型:

  • 路径参数(Path Parameters):如果参数出现在路径中,FastAPI 默认将其视为路径参数。
  • 查询参数(Query Parameters):如果单个参数未在路径中出现,默认会被视为查询参数,即使使用 POST 方法也是如此。
  • 请求体参数(Body Parameters):如果参数类型是一个 Pydantic 模型,则该参数会被默认视为请求体参数。
2. 单个请求体参数

要将单个参数作为请求体参数,需要使用 Body 显式声明。

from fastapi import Body, FastAPI
from typing import Annotated

app = FastAPI()

@app.post("/items/")
async def read_item(item_id: Annotated[int, Body()]):
    return {"item_id": item_id}

测试方法:

  • FastAPI 提供的 Docs 界面:在浏览器中访问 /docs,通过界面测试接口。
  • Requests 库
import requests

url = 'http://127.0.0.1:8009/items/'
res = requests.put(url, json=5)
print(res.text)  # 输出:{"item_id":5}

3. 多个请求体参数

当有多个请求体参数时,可以将它们嵌套在一个字典中传递。

from fastapi import Body, FastAPI
from typing import Annotated

app = FastAPI()

@app.post("/items/")
async def read_item(item_id: Annotated[int, Body()], name: Annotated[str, Body()]):
    return {"item_id": item_id, "name": name}

测试方法:

  • Requests 库
url = 'http://127.0.0.1:8009/items/'
data = {"item_id": 5, "name": "张三"}
res = requests.put(url, json=data)
print(res.text)  # 输出:{"item_id":5,"name":"张三"}

4. Pydantic 模型请求体参数

可以直接将 Pydantic 模型作为请求体参数。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.post("/items/")
async def read_item(item: Item):
    return {"name": item.name, "price": item.price}

测试方法:

  • Requests 库
url = 'http://127.0.0.1:8009/items/'
data = {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6}
res = requests.post(url, json=data)
print(res.text)  # 输出:{"name":"细胞生物学","price":35.8}

5. 混合使用 Path、Query 和请求体参数

可以同时使用路径参数、查询参数和请求体参数。

from fastapi import Body, FastAPI
from typing import Annotated

app = FastAPI()

@app.post("/items/{name}")
async def read_item(name: str, age: int, item_id: Annotated[int, Body()]):
    return {"name": name, "age": age, "item_id": item_id}

测试方法:

  • Requests 库
url = 'http://127.0.0.1:8009/items/张三?age=18'
res = requests.post(url, json=5)
print(res.text)  # 输出:{"name":"张三","age":18,"item_id":5}

6. 多个 Pydantic 模型请求体参数

当函数中有多个 Pydantic 模型参数时,FastAPI 会自动将参数名称作为请求体中的键。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

class User(BaseModel):
    username: str
    full_name: str | None = None

@app.post("/items/")
async def read_item(item: Item, user: User):
    return {"name": item.name, "price": item.price, "user": user}

测试方法:

  • Requests 库
url = 'http://127.0.0.1:8009/items/'
data = {
    "item": {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6},
    "user": {"username": "张三", "full_name": "张三丰"}
}
res = requests.post(url, json=data)
print(res.text)  # 输出:{"name":"细胞生物学","price":35.8,"user":{"username":"张三","full_name":"张三丰"}}

7. 嵌入单个请求体参数

如果希望将单个 Pydantic 模型参数嵌入到 JSON 的键中,可以使用 Body(embed=True)

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.post("/items/")
async def read_item(item: Item = Body(embed=True)):
    return {"name": item.name, "price": item.price}

测试方法:

  • Requests 库
url = 'http://127.0.0.1:8009/items/'
data = {
    "item": {"name": "细胞生物学", "description": "考研书籍", "price": 35.8, "tax": 0.6}
}
res = requests.post(url, json=data)
print(res.text)  # 输出:{"name":"细胞生物学","price":35.8}
8. 总结
  • 路径参数:直接出现在 URL 路径中。
  • 查询参数:通过 URL 的查询字符串传递。
  • 请求体参数:通过 JSON 格式的请求体传递。
  • Pydantic 模型:可以简化复杂的请求体结构,并提供自动校验功能。
  • 混合使用:可以同时使用路径参数、查询参数和请求体参数。

通过以上内容,可以灵活地处理各种类型的参数,满足不同的 API 需求。

FastAPI 额外参数信息详解

1. 核心概念理解
  • 校验与元数据声明:通过Field在数据模型中定义字段约束条件(如数值范围、字符串长度)和描述信息
  • 文档集成机制:所有声明信息会自动转换为OpenAPI规范,驱动交互式文档生成
  • 作用域区分
    • Query/Path/Body:处理请求参数的位置约束
    • Field:专注数据模型内部的字段验证
2. Field 参数深度解析

基础结构示例

from pydantic import BaseModel, Field

class Product(BaseModel):
    sku: str = Field(
        min_length=8,
        max_length=12,
        pattern="^[A-Z]{3}-\\d+$",
        examples=["ABC-123456"]
    )
    stock: int = Field(
        default=0,
        ge=0,
        description="当前库存数量",
        json_schema_extra={"unit": "件"}
    )

常用参数对照表

参数适用类型作用示例值
gt/ge数值类型数值下限约束gt=0
lt/le数值类型数值上限约束lt=100
min_length字符串/集合最小长度限制min_length=5
max_length字符串/集合最大长度限制max_length=20
pattern字符串正则表达式验证pattern="^\\d+$"
default任意类型字段默认值default="new"
title任意类型OpenAPI文档中的字段标题title="产品编号"
description任意类型字段详细说明description="..."
3. 高级配置技巧

自定义文档示例

class ExperimentalData(BaseModel):
    timestamp: float
    value: float = Field(..., gt=0)

    model_config = {
        "json_schema_extra": {
            "examples": [{
                "timestamp": 1717392600.0,
                "value": 3.1415
            }, {
                "timestamp": 1717392601.5,
                "value": 2.7182
            }]
        }
    }

多层级嵌套验证

class Address(BaseModel):
    city: str = Field(max_length=20)
    street: str = Field(description="街道信息")

class UserProfile(BaseModel):
    name: str = Field(min_length=2, max_length=20)
    age: int = Field(ge=18, le=100)
    address: Address = Field(..., description="居住地址")

4. 开发注意事项
  1. 版本兼容性

    • Python 3.8+ 需要使用 Optional 类型声明
    from typing import Optional
    description: Optional[str] = Field(default=None)
    

  2. 性能优化

    • 复杂正则表达式可能影响验证性能
    • 数值范围检查优先于正则表达式验证
  3. 文档增强

    • 使用deprecated参数标记即将废弃的字段
    old_field: str = Field(deprecated=True)
    

5. 调试与验证

请求模拟工具

# 使用HTTPX进行测试
import httpx

async def test_model():
    async with httpx.AsyncClient(app=app, base_url="http://test") as client:
        response = await client.post("/items/7", json={
            "item": {
                "name": "Test",
                "price": 19.99
            }
        })
        assert response.status_code == 200

常见错误处理

  • 422 Unprocessable Entity:表示数据验证失败
  • 错误响应包含详细验证失败信息:
    {
      "detail": [
        {
          "loc": ["body", "item", "price"],
          "msg": "ensure this value is greater than 0",
          "type": "value_error.number.not_gt"
        }
      ]
    }
    

6. 可视化文档效果

配置完成后,访问/docs路由可查看自动生成的交互文档:

  • 模型字段显示所有约束条件
  • 示例数据预填充在请求体编辑器中
  • 参数描述信息显示为帮助文本

OpenAPI 文档示意图

FastAPI 高级功能解析

一、Field 附加参数

在 Pydantic 模型中通过 Field 添加示例数据:

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(examples=["Foo"])
    description: str | None = Field(default=None, examples=["示例描述"])
    price: float = Field(examples=[35.4])
    tax: float | None = Field(default=None, examples=[3.2])

  • 文档效果:在 Swagger UI 的 Schema 部分显示预设示例
  • 数据校验:仅验证字段类型和约束条件,不检查示例内容
二、Body 额外参数

在请求体参数中使用 exampleexamples

from fastapi import Body

body_example = {
    "name": "分子生物学",
    "price": 42.0,
    "tax": 2.8
}

@app.post("/items/{item_id}")
async def update_item(
    item_id: UUID,
    item: Item = Body(embed=True, example=body_example)
):
    return {"item_id": item_id, "item": item}

  • embed=True 表示将请求体包装在 item 字段内
  • 文档显示:Swagger UI 请求体示例显示完整 JSON 结构
三、复杂数据类型处理

FastAPI 支持自动转换的常见类型:

类型输入格式Python 转换
UUID标准 UUID 字符串uuid.UUID
datetimeISO 8601 (e.g., 2024-01-24T07:42:54)datetime.datetime
timeHH:MM:SS[.ffffff]datetime.time
timedelta浮点数(总秒数)datetime.timedelta

示例端点:

@app.post("/events/{event_id}")
async def create_event(
    event_id: UUID,
    start: datetime,
    duration: timedelta = Body(...)
):
    end = start + duration
    return {"event_id": event_id, "end_time": end}

四、数据校验机制

自动校验场景示例:

# 模型定义
class Meeting(BaseModel):
    time: datetime
    participants: conint(ge=1, le=10)  # 1-10人

  • 合法请求:
    {"time": "2024-03-15T14:30:00", "participants": 5}
    

  • 非法请求:
    {"time": "2024-02-30T25:61:00", "participants": 0}
    

    将返回 422 错误,错误详情包含:
    {
      "loc": ["body", "time"],
      "msg": "invalid datetime format",
      "type": "value_error.datetime"
    }
    

五、实践建议
  1. 文档优化技巧:

    • 为枚举类型添加描述:Field(description="物品分类")
    • 使用 examples 展示多种情况:
      price: float = Field(examples=[29.9, 99.0, 159.0])
      

  2. 调试方法:

    # 查看原始请求数据
    print(await request.json())
    # 验证数据转换结果
    print(start_datetime.isoformat())
    

  3. 安全注意事项:

    • 时间字段建议明确时区处理
    • UUID 路径参数自动拦截非法格式请求
六、测试验证流程

from pydantic import validator

class Payment(BaseModel):
    card_number: str = Field(regex=r"^\d{16}$")
    expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")

    @validator("expiry_date")
    def validate_expiry(cls, v):
        month, year = v.split('/')
        if int(year) < datetime.now().year % 100:
            raise ValueError("卡片已过期")
        return v

这些功能组合使用可以创建出:

验证失败时返回的响应示例:

{
    "detail": [
        {
            "loc": ["body", "age"],
            "msg": "ensure this value is less than or equal to 150",
            "type": "value_error.number.not_le",
            "ctx": {"limit_value": 150}
        }
    ]
}

5. 高级校验示例

结合验证器和正则表达式:

  1. 生成测试 UUID:

    import uuid
    test_id = uuid.uuid4()
    

  2. 发送复合类型请求:

    import requests
    
    data = {
        "start": "2024-03-15T09:00:00",
        "duration": 3600.0  # 1小时
    }
    response = requests.post(f"http://api/events/{test_id}", json=data)
    print(response.json())
    

    预期响应包含计算后的结束时间:

    {
      "event_id": "550e8400-e29b-41d4-a716-446655440000",
      "end_time": "2024-03-15T10:00:00"
    }
    

  3. 触发校验错误:

    invalid_data = {"participants": 11}
    response = requests.post("/meetings", json=invalid_data)
    assert response.status_code == 422
    

    以下是对FastAPI数据校验与元数据配置的详细说明:

    1. Field参数扩展校验

    在Pydantic模型中使用Field添加校验规则:

    from pydantic import BaseModel, Field
    
    class User(BaseModel):
        username: str = Field(
            min_length=3,
            max_length=20,
            regex="^[a-zA-Z0-9_]+$",
            example="john_doe",
            description="用户名需包含字母数字和下划线"
        )
        age: int = Field(
            gt=0,
            le=150,
            example=25,
            title="用户年龄"
        )
        tags: list[str] = Field(
            default_factory=list,
            max_items=5,
            example=["python", "web"]
        )
    

    2. 示例数据配置

    两种方式添加示例数据:

    模型内部配置

    class Item(BaseModel):
        name: str
        price: float
        
        class Config:
            schema_extra = {
                "example": {
                    "name": "Wireless Mouse",
                    "price": 29.99
                }
            }
    

    请求体参数配置

    @app.post("/items/")
    async def create_item(item: Item = Body(
        examples={
            "normal": {
                "summary": "标准示例",
                "value": {"name": "键盘", "price": 199.0}
            },
            "discount": {
                "summary": "促销示例",
                "value": {"name": "显示器", "price": 899.0}
            }
        }
    )):
        return item
    

    3. 支持的数据类型

    FastAPI自动处理的数据类型示例:

    类型示例值说明
    datetime.datetime"2023-07-20T14:30:00"ISO 8601格式日期时间
    uuid.UUID"f81d4fae-7dec-11d0-a765-00a0c91e6bf6"标准UUID格式
    EmailStr"user@example.com"邮箱格式验证
    IPvAnyAddress"192.168.1.1"IP地址验证
    PaymentCardNumber"4242424242424242"信用卡号格式验证

    4. 校验机制原理

    当请求到达时,FastAPI会执行以下验证流程:

  4. 类型检查:验证输入是否符合字段声明的类型
  5. 约束验证:检查Field参数定义的条件(如gt=0
  6. 自定义验证:通过@validator装饰器添加的自定义规则
  7. 错误聚合:收集所有验证错误并统一返回
  8. 自文档化的API接口
  9. 强类型约束的数据模型
  10. 自动化的输入验证机制
  11. 清晰的错误反馈信息
  12. 可维护的代码结构
from pydantic import validator

class Payment(BaseModel):
    card_number: str = Field(regex=r"^\d{16}$")
    expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")

    @validator("expiry_date")
    def validate_expiry(cls, v):
        month, year = v.split('/')
        if int(year) < datetime.now().year % 100:
            raise ValueError("卡片已过期")
        return v
 

    对FastAPI数据校验与元数据配置的详细说明:

    1. Field参数扩展校验

    在Pydantic模型中使用Field添加校验规则:

    from pydantic import BaseModel, Field
    
    class User(BaseModel):
        username: str = Field(
            min_length=3,
            max_length=20,
            regex="^[a-zA-Z0-9_]+$",
            example="john_doe",
            description="用户名需包含字母数字和下划线"
        )
        age: int = Field(
            gt=0,
            le=150,
            example=25,
            title="用户年龄"
        )
        tags: list[str] = Field(
            default_factory=list,
            max_items=5,
            example=["python", "web"]
        )
    

    2. 示例数据配置

    两种方式添加示例数据:

    模型内部配置

    class Item(BaseModel):
        name: str
        price: float
        
        class Config:
            schema_extra = {
                "example": {
                    "name": "Wireless Mouse",
                    "price": 29.99
                }
            }
    

    请求体参数配置

    @app.post("/items/")
    async def create_item(item: Item = Body(
        examples={
            "normal": {
                "summary": "标准示例",
                "value": {"name": "键盘", "price": 199.0}
            },
            "discount": {
                "summary": "促销示例",
                "value": {"name": "显示器", "price": 899.0}
            }
        }
    )):
        return item
    

    3. 支持的数据类型

    FastAPI自动处理的数据类型示例:

    类型示例值说明
    datetime.datetime"2023-07-20T14:30:00"ISO 8601格式日期时间
    uuid.UUID"f81d4fae-7dec-11d0-a765-00a0c91e6bf6"标准UUID格式
    EmailStr"user@example.com"邮箱格式验证
    IPvAnyAddress"192.168.1.1"IP地址验证
    PaymentCardNumber"4242424242424242"信用卡号格式验证

    4. 校验机制原理

    当请求到达时,FastAPI会执行以下验证流程:

    1. 类型检查:验证输入是否符合字段声明的类型
    2. 约束验证:检查Field参数定义的条件(如gt=0
    3. 自定义验证:通过@validator装饰器添加的自定义规则
    4. 错误聚合:收集所有验证错误并统一返回

    验证失败时返回的响应示例:

    {
        "detail": [
            {
                "loc": ["body", "age"],
                "msg": "ensure this value is less than or equal to 150",
                "type": "value_error.number.not_le",
                "ctx": {"limit_value": 150}
            }
        ]
    }
    

    5. 高级校验示例

    结合验证器和正则表达式:

    from pydantic import validator
    
    class Payment(BaseModel):
        card_number: str = Field(regex=r"^\d{16}$")
        expiry_date: str = Field(regex=r"^(0[1-9]|1[0-2])\/?([0-9]{4}|[0-9]{2})$")
    
        @validator("expiry_date")
        def validate_expiry(cls, v):
            month, year = v.split('/')
            if int(year) < datetime.now().year % 100:
                raise ValueError("卡片已过期")
            return v
    

    这些功能组合使用可以创建出:

    • 自文档化的API接口
    • 强类型约束的数据模型
    • 自动化的输入验证机制
    • 清晰的错误反馈信息
    • 可维护的代码结构

    嵌套模型的概念

    在 FastAPI 中,嵌套模型是指一个 Pydantic 模型的属性可以是另一个 Pydantic 模型。这种设计允许处理复杂的 JSON 数据结构,并且能够自动进行数据校验、转换和文档生成。

    示例代码

    以下是一个简单的示例,展示了如何在 FastAPI 中使用嵌套模型:

    from fastapi import FastAPI
    from pydantic import BaseModel
    
    app = FastAPI()
    
    class Image(BaseModel):
        url: str
        name: str
    
    class Item(BaseModel):
        name: str
        description: str | None = None
        price: float
        tax: float | None = None
        image: Image | None = None
    
    @app.post("/items/{item_id}")
    async def update_item(item_id: int, item: Item):
        results = {"item_id": item_id, "item": item}
        return results
    

    测试方法

    可以使用 requests 库发送 POST 请求来测试这个 API:

    import requests
    
    url = 'http://127.0.0.1:8000/items/5'
    data = {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2,
        "image": {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        }
    }
    
    res = requests.post(url, json=data)
    print(res.text)  # 输出:JSON 格式的响应数据
    

    深度嵌套

    FastAPI 支持多层嵌套的模型,这意味着可以在一个模型中嵌套另一个模型,而嵌套的模型又可以继续嵌套其他模型。这种设计非常适合处理复杂的 JSON 数据结构。

    自动校验与文档生成

    使用 Pydantic 模型定义嵌套结构后,FastAPI 会自动进行数据校验,确保传入的数据符合模型定义。同时,FastAPI 还会自动生成 API 文档,展示每个字段的类型和描述,方便开发者理解和使用 API。

    总结

    通过使用 FastAPI 的嵌套模型功能,可以轻松处理复杂的 JSON 数据结构,并获得自动校验、数据转换和文档生成的功能。这种设计使得 API 开发更加高效和可靠。

    FastAPI Cookie 参数详解

    定义 Cookie 参数

    在 FastAPI 中,Cookie 参数可以通过 Cookie 工厂函数来声明。这种方式与 Query 参数和 Path 参数的声明方式类似,但需要明确指定参数来自 Cookie。

    from typing import Annotated
    from fastapi import Cookie, FastAPI
    
    app = FastAPI()
    
    @app.get("/items/")
    async def read_items(ads_id: Annotated[str | None, Cookie()] = None):
        return {"ads_id": ads_id}
    

    在上述代码中,ads_id 是一个可选的 Cookie 参数,类型为 strNoneCookie() 工厂函数告诉 FastAPI 该参数来自 Cookie。

    使用 requests 库测试

    为了测试上述代码,可以使用 requests 库发送带有 Cookie 的 GET 请求。

    import requests
    
    url = 'http://127.0.0.1:8009/items/'
    headers = {"Cookie": "ads_id=你好"}
    res = requests.get(url, headers=headers)
    print(res.text)  # 输出:{"ads_id":"你好"}
    

    如果未设置 ads_id Cookie,则返回值为 {"ads_id": null}。确保 headers 中的 Cookie 格式正确,例如 key=value

    常见问题及解决方法

    问题 1:无法识别 Cookie

    • 原因:可能是因为 headers 格式不正确或服务端未正确解析 Cookie。
    • 解决方法
      • 确保 headers 中的 Cookie 格式为 key=value
      • 检查 FastAPI 服务端是否正常运行。

    问题 2:Cookie 值为空

    • 原因:未传递正确的 Cookie 或未设置默认值。
    • 解决方法
      • 确保请求中包含正确的 Cookie。
      • 在路径操作函数中为 Cookie 参数设置默认值。
    总结
    • Cookie 参数:通过 Cookie 工厂函数声明,可以从 HTTP 请求中提取 Cookie 数据。
    • 声明方式:与 Query 参数和 Path 参数类似,但需要明确使用 Cookie
    • 测试方法:使用 requests 库发送带有 Cookie 头的请求,验证功能是否正常。

    通过以上内容,可以灵活地在 FastAPI 中处理 Cookie 数据,满足各种应用场景的需求。

    FastAPI Header 参数详解

    1. 概述

    FastAPI 提供了 Header 工厂函数,用于从 HTTP 请求头中提取参数。与 Query、Path 和 Cookie 参数类似,Header 参数需要显式声明,以避免被误解为其他类型的参数。

    2. 基本用法

    通过 Header() 声明参数,FastAPI 会自动从请求头中提取对应的值。以下是一个简单的示例:

    from fastapi import FastAPI, Header
    
    app = FastAPI()
    
    @app.get("/items/")
    async def read_items(user_agent: str = Header(None)):
        return {"User-Agent": user_agent}
    

    • user_agent 参数:通过 Header() 声明,提取请求头中的 User-Agent
    • 默认值:如果请求中未包含 User-Agent,返回值为 None
    3. 自定义 Header 名称

    默认情况下,FastAPI 会将参数名转换为小写并添加连字符(如 user_agent 对应 User-Agent)。如果需要使用自定义的 Header 名称,可以通过 alias 参数指定:

    @app.get("/items/")
    async def read_items(custom_header: str = Header(None, alias="X-Custom-Header")):
        return {"Custom-Header": custom_header}
    

    4. 多值 Header

    某些 Header 可能包含多个值(如 Accept-Language),可以通过 List 类型来接收这些值:

    from typing import List
    
    @app.get("/items/")
    async def read_items(accept_language: List[str] = Header(None)):
        return {"Accept-Language": accept_language}
    

    5. 测试方法

    使用 requests 库发送带有自定义 Header 的 GET 请求,验证 FastAPI 的 Header 参数功能:

    import requests
    
    url = 'http://127.0.0.1:8009/items/'
    headers = {"User-Agent": "test", "X-Custom-Header": "custom-value"}
    res = requests.get(url, headers=headers)
    print(res.text)  # 输出:{"User-Agent":"test", "Custom-Header":"custom-value"}
    
    6. 总结
    • Header 参数声明:使用 Header() 明确指定参数来自请求头。
    • 自定义 Header 名称:通过 alias 参数指定自定义的 Header 名称。
    • 多值 Header:使用 List 类型接收包含多个值的 Header。
    • 测试:通过 requests 库模拟请求,验证 Header 参数功能。

    FastAPI:Web框架学习参考

    http://www.datawhale.cn/learn/summary/164

    http://github.com/datawhalechina/wow-fullstack/tree/main/tutorial/FastAPI

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值