当前位置: 首页 > news >正文

FastAPI系列06:FastAPI响应(Response)

FastAPI响应(Response)

    • 1、Response入门
    • 2、Response基本操作
      • 设置响应体(返回数据)
      • 设置状态码
      • 设置响应头
      • 设置 Cookies
    • 3、响应模型 response_model
    • 4、响应类型 response_class
      • Response派生类
      • 自定义response_class


在“FastAPI系列05:FastAPI请求(Request)”一节中我们详细了解了FastAPI程序对请求参数的校验和处理,在程序中这些处理后的数据将被送入业务逻辑单元,进行进一步的处理,最终向客户端返回HTTP响应。本节我们通过FastAPI实现大文件断点续传等示例详细讨论FastAPI向客户端返回HTTP响应的内容。

1、Response入门

在HTTP协议中,HTTP响应报文主要由三部分组成:

  1. 状态行 (Status Line)
    状态行包含: HTTP版本号(如HTTP/1.1、HTTP/2。)、状态码(- 如 200、404、500,代表服务器对请求的处理结果。)、状态描述( 如 OK、Not Found、Internal Server Error,是简单的人类可读的描述)

  2. 响应头部 (Response Headers)
    一系列 键值对,告诉客户端一些关于响应报文本身或者服务器的信息。常见的响应头字段有:

    • Content-Type: 指定返回内容的类型,比如 text/html; charset=UTF-8
    • Content-Length: 返回内容的长度(单位:字节)
    • Server: 服务器软件的信息
    • Set-Cookie: 设置客户端的 Cookie
    • Cache-Control: 缓存策略
    • Location: 重定向地址(配合 301/302 状态码)
  3. 响应主体 (Response Body)
    主体部分是服务器真正返回给客户端的数据内容。比如:

    • HTML 代码
    • 图片
    • JSON 格式的数据
    • 二进制文件流

一个常见的HTTP响应报文大致如下:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 137
Connection: keep-alive
Server: nginx/1.18.0<!DOCTYPE html>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>

在FastAPI中可以使用Response或其派生对象方便地设置状态码、响应头以及响应主体。

2、Response基本操作

设置响应体(返回数据)

在FastAPI中,可以通过直接返回 dict / list(这时FastAPI 自动转成 JSON)、返回 HTML、文件、流式响应或用 Response 或 StreamingResponse 等手动控制来设置响应体。

from fastapi import FastAPIapp = FastAPI()@app.get("/json")
def read_json():return {"message": "Hello, World"}

设置状态码

FastAPI中定义了status枚举,用于在程序中指定响应状态码。

from fastapi import FastAPI, statusapp = FastAPI()@app.post("/create", status_code=status.HTTP_201_CREATED)
def create_item():return {"msg": "Item created"}

设置响应头

可以用 Response 或 JSONResponse 手动设置头部,也可以在路由里加 response_model、response_class等参数。

from fastapi import FastAPI
from fastapi.responses import JSONResponseapp = FastAPI()@app.get("/custom-header")
def custom_header():content = {"message": "Custom header"}headers = {"X-Custom-Header": "FastAPI"}return JSONResponse(content=content, headers=headers)

设置 Cookies

使用 Response.set_cookie() 方法

from fastapi import FastAPI, Responseapp = FastAPI()@app.get("/set-cookie")
def set_cookie(response: Response):response.set_cookie(key="session_id", value="abc123")return {"message": "Cookie set"}

3、响应模型 response_model

在FastAPI中,response_model主要用来声明和验证返回数据格式。FastAPI 会根据定义的 response_model,完成:

  • 自动校验返回的数据是否符合
  • 自动生成 OpenAPI 文档(自动文档超好看)
  • 自动进行数据的序列化(比如只返回你指定的字段)
from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class UserOut(BaseModel):id: intname: str@app.get("/user", response_model=UserOut)
def get_user():# 返回一个字典,FastAPI会根据UserOut去校验和生成响应return {"id": 1, "name": "Alice", "password": "123456"}

说明

  • password字段不会返回给前端!因为 UserOut 没有定义 password 字段。

4、响应类型 response_class

在FastAPI中, response_class主要用来指定响应体的类型和格式。FastAPI 会根据response_class控制返回的内容格式,比如 JSON、HTML、纯文本、文件、流式响应等等。

Response派生类

FastAPI提供了JSONResponse、HTMLResponse、PlainTextResponse、FileResponse、StreamingResponse、RedirectResponse等response_class用于定义响应体的类型和格式,它们均派生自 Response 类。

Response
+content
+status_code
+headers
+media_type
+background
JSONResponse
+media_type = "application/json"
+render()
HTMLResponse
+media_type = "text/html"
+render()
PlainTextResponse
+media_type = "text/plain"
+render()
FileResponse
+return files
StreamingResponse
+streaming data
UJSONResponse
+faster JSON serialization

一般情况下,FastAPI默认使用JSONResponse,返回application/json 响应。下面示例中指定了response_class为HTMLResponse以返回 HTML 字符串。

from fastapi import FastAPI
from fastapi.responses import HTMLResponseapp = FastAPI()@app.get("/html", response_class=HTMLResponse)
def get_html():return "<h1>Hello, HTML</h1>"

自定义response_class

我们可以通过以下几步自定义一个 Response 类:

  1. 继承自 fastapi.Response 或 starlette.responses.Response
  2. 重写 render() 方法,告诉 FastAPI:怎么把内容转成字节流(bytes)
  3. 还可以自定义 media_type(Content-Type)

自定义一个返回 .csv 文件的 Response

from fastapi import FastAPI
from starlette.responses import Responseclass CSVResponse(Response):media_type = "text/csv"def render(self, content: str) -> bytes:# 直接把字符串编码成bytes返回return content.encode("utf-8")app = FastAPI()@app.get("/csv", response_class=CSVResponse)
def get_csv():csv_content = "id,name\n1,Alice\n2,Bob"return csv_content

自定义一个加密后的 JSON Response

import json
from fastapi import FastAPI
from starlette.responses import Response
import base64class EncryptedJSONResponse(Response):media_type = "application/json"def render(self, content: dict) -> bytes:json_data = json.dumps(content)# 简单加密:base64编码(真实项目要用AES/自定义加密)encrypted = base64.b64encode(json_data.encode("utf-8"))return encryptedapp = FastAPI()@app.get("/encrypted", response_class=EncryptedJSONResponse)
def get_encrypted():return {"msg": "secret data"}

自定义一个超大文件分块下载的 Response

from starlette.responses import StreamingResponseclass LargeFileResponse(StreamingResponse):def __init__(self, file_path: str, chunk_size: int = 1024 * 1024):generator = self.file_chunk_generator(file_path, chunk_size)super().__init__(generator, media_type="application/octet-stream")self.headers["Content-Disposition"] = f"attachment; filename={file_path.split('/')[-1]}"@staticmethoddef file_chunk_generator(file_path: str, chunk_size: int):with open(file_path, mode="rb") as file:while chunk := file.read(chunk_size):yield chunk@app.get("/download")
def download_big_file():return LargeFileResponse("bigfile.zip")

实现断点续传(支持 Range )的 StreamingResponse
HTTP协议有个标准:Range 请求头。客户端可以在请求头里加Range: bytes=1000-,意思是:“我只要从第1000个字节开始的数据,后面的。”
这样可以实现大文件断点续传或音频、视频流式播放(在线播放时,只请求一部分)。

from fastapi import FastAPI, Request, HTTPException
from starlette.responses import StreamingResponse
import osapp = FastAPI()# 分块读取文件
def range_file_reader(file_path: str, start: int = 0, end: int = None, chunk_size: int = 1024 * 1024):with open(file_path, "rb") as f:f.seek(start)remaining = (end - start + 1) if end else Nonewhile True:read_size = chunk_size if not remaining else min(remaining, chunk_size)data = f.read(read_size)if not data:breakyield dataif remaining:remaining -= len(data)if remaining <= 0:break@app.get("/download")
async def download_file(request: Request):file_path = "bigfile.zip"  # 换成你的大文件路径if not os.path.exists(file_path):raise HTTPException(status_code=404, detail="File not found")file_size = os.path.getsize(file_path)range_header = request.headers.get("range")if range_header:# 解析 range头bytes_unit, byte_range = range_header.split("=")start_str, end_str = byte_range.split("-")start = int(start_str) if start_str else 0end = int(end_str) if end_str else file_size - 1if start >= file_size:raise HTTPException(status_code=416, detail="Range Not Satisfiable")content_length = end - start + 1headers = {"Content-Range": f"bytes {start}-{end}/{file_size}","Accept-Ranges": "bytes","Content-Length": str(content_length),"Content-Type": "application/octet-stream","Content-Disposition": f"attachment; filename={os.path.basename(file_path)}",}return StreamingResponse(range_file_reader(file_path, start, end),status_code=206,  # Partial Contentheaders=headers,)# 没有Range头,普通全量返回headers = {"Content-Length": str(file_size),"Content-Type": "application/octet-stream","Content-Disposition": f"attachment; filename={os.path.basename(file_path)}",}return StreamingResponse(range_file_reader(file_path),status_code=200,headers=headers,)

在此基础上,还可以:

  • 支持多段 Range(比如同时请求0-100, 200-300),但是这个场景很少,比较复杂
  • 限制最大单次传输大小(保护服务器)
  • 支持 gzip 压缩返回(如果是文本文件)
  • 加上异步读取(aiofiles)提升 IO 性能

总之,通过自定义response_class可以实现非常多且实用的功能。

http://www.xdnf.cn/news/180721.html

相关文章:

  • leetcode--盛最多水的容器,接雨水
  • 数值分析、数值代数之追赶法
  • Linux课程五课---Linux进程认识1
  • MySQL----查询
  • 树莓派超全系列教程文档--(43)树莓派内核简介及更新
  • 机器学习基础——Seaborn使用
  • C++11
  • 自然语言处理之机器翻译:Statistical Machine Translation(SMT)的评估方法解析与创新实践
  • 小集合 VS 大集合:MySQL 去重计数性能优化
  • 常用第三方库:sqflite数据库应用
  • Python语言基础知识详解:数据类型及运算
  • 【MQ篇】RabbitMQ之消费失败重试!
  • 2、Linux操作系统下,ubuntu22.04版本安装搜狗输入法
  • <PLC><汇川><工控>汇川PLC实现光纤缠绕设备
  • ollama的若干实践
  • Step1X-Edit: A practical framework for general image editing
  • PaddleX的安装
  • Moment 在 JavaScript 中解析、校验、操作、显示日期和时间
  • web 开发中,前端部署更新后,该怎么通知用户刷新
  • 新闻数据接口开发指南:从多源聚合到NLP摘要生成
  • 一些可用于监控服务器响应时间稳定性的工具
  • 【神经网络与深度学习】端到端方法和多任务学习
  • 来自B站AIGC科技官的“vLLM简介“视频截图
  • 音频转base64
  • 基于c++的LCA倍增法实现
  • log4cpp进阶指南
  • Dart中一个类实现多个接口 以及Dart中的Mixins
  • NestJS + Kafka 秒杀系统完整实践总结
  • 大语言模型的“模型量化”详解 - 04:KTransformers MoE推理优化技术
  • Android 理清 Gradle、AGP、Groovy 和构建文件之间的关系