表单字段 & json请求体 的区别

1. 外形不一样

  • 表单Form:一串拼接文本,像一串串串号
    name=小明&age=20&sex=男
  • JSON请求体:规整大括号包裹,像填好的档案表
    {"name":"小明","age":20}

2. 装东西能力不同

  • 表单:只能装零散简单文字、数字,不能嵌套多层数据、不能装数组
    • 除此以外,表单还可以传文件,json请求体不行。
  • JSON:随便装,多层嵌套、列表数组都没问题,只是能装复杂的数据而已,不能传二进制文件

3. 发送身份不一样

  • 表单:浏览器原生页面点击提交按钮默认发的格式
  • JSON:手机APP、Vue/React网页、接口调试工具常用格式

4. FastAPI接收写法

  • 表单:单个字段挨个接收
def login(name:str=Form(), pwd:str=Form()):
  • JSON:统一用模型整体接收
def login(user:UserModel):

5. 适用场景直白区分

  • 老式网页登录、简单提交、传文件 → 用表单
  • 手机端、前后端分离、复杂数据交互 → 用JSON

为什么表单字段和 JSON 请求体不能在同一个路由中同时使用?

表单数据以"字段"的形式发送,不是 JSON。因此不能将 Form 参数声明为 Pydantic 模型。表单字段和 JSON 请求体不能在同一个路由中同时使用。

第一句:

表单数据以"字段"形式发送,不是 JSON → 不能用 Pydantic 模型接收

为什么?

表单长这样:

username=张三&password=123&age=20

它是一整串扁平的字符串,没有层级、没有结构。

而 Pydantic 模型是给 JSON 结构化数据 用的:

{ "username": "张三", "password": "123" }

结论:

表单是扁平字符串 → 不能直接塞进 Pydantic 模型
只能一个字段一个字段接收:username: str = Form()


第二句:

表单字段 和 JSON 请求体 不能在同一个路由里同时使用

为什么?

因为一个 HTTP 请求,只能有一种请求体格式

要么是:

  • application/json(JSON格式)
    要么是:
  • application/x-www-form-urlencoded(表单格式)
    要么是:
  • multipart/form-data(文件表单格式)

一个请求不能同时发两种格式!
就像:
你不能同时用中文和英文写同一句话,别人看不懂。

所以:
同一个接口,不能既接收 JSON,又接收表单!


用最通俗的比喻总结

JSON = 结构化档案(分层、嵌套)

表单 = 一串扁平字符串(无结构)

一个请求 = 一个信封

信封里只能装一种内容
要么装档案(JSON)
要么装一串文字(表单)

不能同时装两种!


代码里的规则(必须记住)

✅ 可以:纯 JSON

def login(user: User):  # JSON

✅ 可以:纯 Form

def login(username: str = Form(), password: str = Form()):

❌ 不可以:JSON + Form 同时写(报错!)

def login(user: User, username: str = Form()):

❌ 不可以:想用 Pydantic 接收表单(报错!)

def login(user: User = Form()):

最终超级大白话结论

  1. 表单是扁平字符串 → 只能一个字段一个字段收,不能用 Pydantic 模型收
  2. JSON 是结构化数据 → 必须用 Pydantic 模型收
  3. 一个接口只能选一种:要么 JSON,要么表单,不能两个都要
  4. 传文件 → 必须用表单
  5. 传复杂数据 → 必须用 JSON

一个请求,一种格式;JSON 用模型,表单用字段,不能混用!

什么是Starlette?

FastAPI 把 Starlette 当作自己的 “底层骨架”
就像:
Starlette = 房子的地基 + 框架
FastAPI = 精装修好的房子

Starlette 是一个轻量级 Python Web 框架FastAPI 完全使用了 Starlette,并在上面加了自动文档、数据校验等功能


ASGI 与异步编程

ASGI(Asynchronous Server Gateway Interface)异步服务器网关接口,Python Web 的新一代 “通信协议”,专门支持异步。

await asyncio.gather(任务1, 任务2, 任务3…)

asyncio.gather () = 让多个异步任务 同时、一起、并行跑!跑完之后,一次性把所有结果返回给你。

import asyncio

# 异步任务1
async def task1():
    await asyncio.sleep(1)  # 模拟耗时1秒
    print("任务1完成")
    return "结果1"

# 异步任务2
async def task2():
    await asyncio.sleep(1)
    print("任务2完成")
    return "结果2"

# 主函数
async def main():
    # ✅ 同时跑两个任务!不是一个跑完再跑一个
    result1, result2 = await asyncio.gather(
        task1(),
        task2()
    )

    print("全部结果:", result1, result2)

# 运行
asyncio.run(main())

运行结果

任务1完成
任务2完成
全部结果:结果1 结果2

重点:
两个任务只花了 1 秒,不是 2 秒!
因为它们同时运行了。

Fastapi 中何时使用异步?

适合异步的场景

  • 数据库操作
  • 网络请求(API调用)
  • 文件 I/O 操作
  • 长时间等待的操作

不适合异步的场景

  • CPU密集型计算
  • 简单的数据处理
  • 没有 I/O 等待的操作

REST API 设计原则

REST(Representational State Transfer,表述性状态转移)是一种 Web API 设计风格。用 HTTP 请求方式 + URL 地址,直观表达对数据的增删改查,风格统一、易懂规范。

RESTful URL设计原则

用名词,不用动词;
用复数,不用单数;
用 HTTP 方法表示操作,不用写在 URL 里;
层级清晰,参数放查询。

7条设计原则

1. 只用名词,不用动词

URL 只代表资源(数据),不代表动作。

✅ 正确
/users
/orders
/products

❌ 错误
/getUser
/createOrder
/deleteProduct


2. 资源用复数,更规范、更通用

企业 99% 都用复数!

✅ 正确
/users
/orders
/articles

❌ 不推荐
/user
/order


3. 用 HTTP 方法表示操作,不写进 URL

这是 REST 最核心的设计!

方法 作用 示例
GET 查询 GET /users
POST 新建 POST /users
PUT 全量更新 PUT /users/1
PATCH 局部更新 PATCH /users/1
DELETE 删除 DELETE /users/1

4. 层级关系用 / 表示,清晰直观

子资源放在父资源后面

✅ 正确

  • 一个用户的所有订单
    /users/1/orders

  • 一篇文章的评论
    /articles/12/comments


5. 小写字母,用中横线 - 分隔,不用下划线

✅ 正确
/user-orders
/shopping-cart

❌ 不规范
/userOrders
/user_orders


6. 过滤、分页、排序参数 放 ? 查询参数

不放进路径里!

✅ 正确

  • 分页
    /users?page=1&size=10

  • 筛选
    /products?category=book&price_min=10

  • 排序
    /articles?sort=create_time,desc

✅ 正确写法(参数放?后面)
GET /users?page=1&size=10&sort=age

❌ 不规范(参数放在路径里)

GET /users/page/1/size/10/sort/age


7. 版本号放前面,方便升级

✅ 正确
/v1/users
/v2/orders


最标准的 RESTful URL 示例大全(背下来)

用户

  • 获取所有用户 → GET /users
  • 获取单个用户 → GET /users/1
  • 新建用户 → POST /users
  • 更新用户 → PUT /users/1
  • 删除用户 → DELETE /users/1

用户的订单

  • 获取用户1的所有订单 → GET /users/1/orders
  • 获取用户1的某个订单 → GET /users/1/orders/10

最容易犯的错误(一定要避开)

/getUserInfo
/api/user/delete
/userInfo.action
/UserList

这些都不是 RESTful


超级总结(一句话记住)

RESTful URL = 复数名词 + 层级清晰 + HTTP方法表示操作 + 参数放查询

HTTP 方法与状态码

HTTP 方法

我用最简单、最通俗、最实用的方式,一次性把 HTTP 方法 + HTTP 状态码 讲透!
这是 RESTful API 最核心的基础,面试、工作必问必用。

一、什么是 HTTP 方法?

就是浏览器/前端 告诉后端:你想对数据做什么!

就像你对服务员说:

  • 拿来 = GET
  • 新增 = POST
  • 替换 = PUT
  • 修改 = PATCH
  • 删掉 = DELETE

5 个最常用 HTTP 方法(必须背会)

方法 含义 作用 对应操作
GET 获取 查询数据
POST 提交 新建数据
PUT 更新 全量替换数据 改(全量)
PATCH 修补 局部修改数据 改(局部)
DELETE 删除 删除数据

最直观例子(用户接口)

  • GET /users → 获取所有用户
  • GET /users/1 → 获取 1 号用户
  • POST /users → 新建用户
  • PUT /users/1 → 替换 1 号用户全部信息
  • PATCH /users/1 → 只改 1 号用户的名字/年龄
  • DELETE /users/1 → 删除 1 号用户

二、什么是 HTTP 状态码?

就是后端 告诉前端:这次请求结果怎么样!

就像服务员告诉你:

  • 200 = 好了,没问题
  • 400 = 你参数错了
  • 404 = 找不到东西
  • 500 = 服务器崩了

必背 10 个状态码(全世界通用)

1xx:消息(不用管)
2xx:成功(一切正常)
  • 200 OK → 查询/修改成功
  • 201 Created → 创建成功(POST)
  • 204 No Content → 删除成功
3xx:重定向(很少用)
4xx:前端错了(客户端错误)
  • 400 Bad Request → 参数错误
  • 401 Unauthorized → 未登录
  • 403 Forbidden → 没权限
  • 404 Not Found → 资源不存在
  • 405 Method Not Allowed → 方法不允许
  • 409 Conflict # 资源冲突
  • 422 Unprocessable Entity # 数据验证失败
  • 429 Too Many Requests # 请求过于频繁
5xx:后端错了(服务器错误)
  • 500 Internal Server Error → 服务器崩溃
  • 502 Bad Gateway → 网关错误
  • 503 Service Unavailable # 服务不可用

三、HTTP 方法 + 状态码 标准搭配(企业规范)

1. GET 查询

  • 成功:200

2. POST 新建

  • 成功:201

3. PUT / PATCH 修改

  • 成功:200

4. DELETE 删除

  • 成功:204

四、FastAPI 里如何使用?

from fastapi import FastAPI, status

app = FastAPI()

# 查询 → 200
@app.get("/users", status_code=status.HTTP_200_OK)
def get_users():
    return {"msg": "查询成功"}

# 新建 → 201
@app.post("/users", status_code=status.HTTP_201_CREATED)
def create_user():
    return {"msg": "创建成功"}

# 删除 → 204
@app.delete("/users/{id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_user():
    return

五、终极总结(一句话记住)

HTTP 方法 = 前端告诉后端要做什么

HTTP 状态码 = 后端告诉前端结果怎么样

最简记忆表

  • GET → 查询 → 200
  • POST → 新增 → 201
  • PUT/PATCH → 修改 → 200
  • DELETE → 删除 → 204
  • 找不到 → 404
  • 没权限 → 401
  • 服务器崩 → 500

JSON数据格式

JSON = 一种前后端通用的数据格式,长得像 Python 字典,全平台都能读懂。

JSON 支持哪些数据类型?

JSON 只有 6 种基础类型:

  • 字符串(“hello”)
  • 数字(123 / 1.23)
  • 布尔(true / false)
  • 数组([1,2,3])
  • 对象({…})【这里的对象指 带花括号的 键值对】
  • null

JSON 对象的特点:

  • 只有 字符串键
  • 只能放 JSON 支持的 6 种基础类型
  • 没有函数、没有类、没有复杂类型
  • 前端、Java、Go 都能看懂

JSON 不支持什么?(非常重要)

这些 Python 类型 不能直接转 JSON:

  • datetime 时间
  • Decimal 高精度小数
  • bytes 字节
  • 对象 / 类实例 (比如:ORM模型、datetime、自定义对象)

所以必须序列化(转成字符串 / 数字)。

把 Python 对象 → 转成 JSON 格式 = 序列化
序列化 = 把内存里的对象 → 变成可传输、可存储的字符串 / 格式
反序列化 = 把 JSON 字符串 → 变回 Python 对象

Pydantic 模型的配置类

作用:告诉 Pydantic 怎么格式化、怎么序列化、怎么校验数据

下面的写法——Config配置类是Pydantic V1版本中的写法,V2版本写法是 使用模型配置 ConfigDict 。V2 向下兼容 V1 的 Config 内部类,所以老代码能跑。

from datetime import datetime
from decimal import Decimal
from typing import Optional, List
from pydantic import BaseModel, Field
import json

# JSON 数据格式规范
class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    full_name: Optional[str] = None
    is_active: bool = True
    created_at: datetime
    updated_at: Optional[datetime] = None
   
    # JSON 序列化配置
    class Config:  # 【Pydantic V1 版本写法】
        # 允许使用字段别名
        allow_population_by_field_name = True
        # JSON 编码器
        json_encoders = {
            datetime: lambda v: v.isoformat(),
            Decimal: lambda v: float(v)
        }

(模型配置/Config配置类 里的) 序列化配置 json_encoders

json_encoders = {
	datetime: lambda v: v.isoformat(),
	Decimal: lambda v: float(v)
}

作用:
遇到哪些特殊类型,自动用指定方式转成 JSON
它是一个字典:{ 类型: 转换函数 }

示例:

datetime: lambda v: v.isoformat()
意思:
当遇到 datetime 时间对象时自动调用 isoformat () 转成标准时间字符串


例如:
# Python 对象(JSON不认识)
datetime(2025, 5, 20, 18, 30)

# 自动变成(JSON认识)
"2025-05-20T18:30:00"
Decimal: lambda v: float(v)
意思:
当遇到 Decimal 高精度小数时自动转成普通浮点数


例如:
# Python 对象(JSON不认识)
Decimal('19.99')

# 自动变成
19.99

最常用的3个编码器

json_encoders = {
    datetime: lambda v: v.isoformat(),    # 时间
    Decimal: lambda v: float(v),          # 高精度小数
    bytes: lambda v: v.decode("utf-8")    # 字节
}

什么时候用 utf-8,什么时候用 base64?(超级重要)

  1. bytes 是普通文本
    用:

    bytes: lambda v: v.decode("utf-8")
    
  2. bytes 是图片、文件、PDF、加密数据、二进制串(99% 场景)
    用:

    bytes: lambda v: base64.b64encode(v).decode("utf-8")
    
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐