好记性不如烂笔头
内容来自 [ 面试宝典-高级难度Fast API面试题合集](https://offer.houxu6.top/tag/Fast API)
问: 请简述FastAPI的优缺点,并给出一些应用场景。
FastAPI 是一个现代、快速且高性能的 Python Web 框架,用于构建 RESTful API 和 Web 应用。它基于标准的 Python 类型提示,并结合了 Starlette 和 Pydantic 等库的功能。
优点:
- 高性能:FastAPI 使用异步编程模型和轻量级框架Starlette,使得其性能与 Node.js 和 Go 相媲美。
- 类型安全:通过使用 Python 的类型提示,FastAPI 能够提供自动文档生成、数据验证以及错误处理等功能。
- 易于学习和使用:FastAPI 有直观的语法,使得开发者能够快速上手并高效地开发项目。
- 丰富的功能:支持 OAuth2 和 JWT 认证、OpenAPI 规范、WebSocket 和 GraphQL 等特性。
- 可扩展性:FastAPI 可以轻松与其他库和服务集成,如数据库 ORM(如 SQLAlchemy)、身份验证库等。
- 强大的文档:FastAPI 自动从代码生成交互式的 API 文档,方便用户查看和测试接口。
缺点:
- 社区规模相对较小:尽管 FastAPI 正在快速增长,但相比其他成熟的 Web 框架,它的社区和生态系统可能还相对较小。
- 学习曲线:虽然 FastAPI 努力使自己对新手友好,但对于没有接触过类型提示或异步编程的开发者来说,仍有一定的学习曲线。
- 兼容性问题:由于 FastAPI 需要 Python 3.6+ 并依赖于一些特定库,因此在某些环境下可能存在兼容性问题。
应用场景:
- 微服务架构:FastAPI 可以很好地作为微服务的一部分,利用其高效率和轻量化的特点。
- API 后端开发:FastAPI 提供了一个强大而灵活的平台来创建 RESTful API,适用于各种类型的后端应用。
- 实时通信应用:FastAPI 支持 WebSocket,适合需要实时更新的应用,如聊天系统或在线游戏。
- 数据驱动的 Web 应用:FastAPI 可以与流行的数据库 ORM 集成,为数据密集型应用提供良好的支持。
- 机器学习/人工智能项目的部署:FastAPI 可以帮助将 ML 或 AI 模型部署为 RESTful API,使其可以被其他应用程序调用。
总之,FastAPI 是一个理想的工具,特别是在你需要高性能、类型安全和易用性的场景下。
问: 请解释一下什么是依赖注入,以及FastAPI是如何实现的?
依赖注入(Dependency Injection,简称DI)是一种软件设计模式,它有助于解耦应用程序的组件。在依赖注入中,一个对象的依赖关系不是由该对象自己创建或管理的,而是由外部容器或框架来提供和管理。
这种做法有以下优点:
- 降低耦合度:对象不需要知道如何创建它们的依赖项,这使得代码更易于测试、理解和维护。
- 更好的可扩展性:可以通过更改配置而不是修改代码来替换或添加依赖项。
- 更容易进行单元测试:可以在测试时轻松地替换依赖项为模拟对象,以便更好地隔离测试场景。
FastAPI 在其设计中实现了依赖注入机制,允许开发者以声明式的方式定义依赖项,并在需要的地方自动注入它们。以下是 FastAPI 中实现依赖注入的基本步骤:
-
定义依赖项:
创建一个类或函数作为依赖项,通常会包含一些业务逻辑或者服务功能。 -
装饰器标记:
使用Depends
装饰器将依赖项标记为可注入的。这个装饰器告诉 FastAPI 在调用依赖此依赖项的函数时应提供它。
from fastapi import Depends
class MyDependency:
def __init__(self, some_parameter: str):
self.some_parameter = some_parameter
def my_dependency(some_parameter: str) -> MyDependency:
return MyDependency(some_parameter)
@my_dependency # 或者 @Depends(my_dependency)
async def some_endpoint(dependency: MyDependency):
pass
在这个例子中,MyDependency
类被标记为可注入的,然后在 some_endpoint
函数中通过 @my_dependency
装饰器注入。
-
自动注入:
当 FastAPI 接收到请求并开始处理路由时,它会检查哪些参数是依赖项,并根据需要实例化这些依赖项,然后将其传递给相应的处理函数。 -
生命周期管理:
FastAPI 还支持依赖项的多种生命周期策略,如单例(Singleton)、线程安全的并发单例(Scoped),以及每次请求都会创建新实例的瞬态(Transient)策略。这使得开发者可以根据需求调整依赖项的行为。 -
依赖顺序:
如果一个依赖项依赖于另一个依赖项,FastAPI 可以自动解决这些依赖关系,确保按照正确的顺序初始化和注入依赖项。
通过这种方式,FastAPI 提供了一个直观且强大的依赖注入系统,帮助开发者构建松散耦合的应用程序,并简化了依赖管理过程。
问: 请简述一下什么是OpenAPI和Swagger,以及FastAPI是如何支持这些规范的?
OpenAPI 和 Swagger 是与 API 开发相关的规范和工具。
-
OpenAPI:
OpenAPI(以前称为 Swagger 规范)是一个用于定义 RESTful API 的标准格式。它提供了一种描述 API 结构、端点、请求参数、响应数据等的通用语言,使得开发者可以更容易地理解和使用 API。OpenAPI 规范支持 JSON 和 YAML 格式,并且是跨语言、跨平台的。 -
Swagger:
Swagger 是一个围绕 OpenAPI 规范构建的工具集。它包括了用于生成、可视化、测试和文档化 API 的各种工具。例如,Swagger UI 是一个交互式的 Web 界面,它可以读取 OpenAPI 规范文件并生成易于使用的 API 文档。
FastAPI 通过集成 Starlette 和 Pydantic 库,实现了对 OpenAPI 和 Swagger 的支持:
-
类型提示和模型:
FastAPI 使用 Python 类型提示来推断 API 结构,并将其转换为 OpenAPI 规范。同时,FastAPI 利用 Pydantic 库进行数据验证,确保请求和响应的数据符合预期的结构。 -
自动生成 OpenAPI 规范:
当 FastAPI 应用运行时,它会自动创建一个 OpenAPI 规范文件(通常是openapi.json
或openapi.yaml
),该文件包含了所有路由、参数、请求体、响应等内容的详细信息。 -
内置 Swagger UI 支持:
FastAPI 内置了对 Swagger UI 的支持,可以通过访问/docs
或/redoc
路径来查看应用的交互式 API 文档。这些文档直接从生成的 OpenAPI 规范中获取信息,因此始终保持最新。 -
插件和扩展:
FastAPI 还允许开发者添加额外的插件或扩展来增强其对 OpenAPI 和 Swagger 的支持。这可能包括定制错误处理、添加安全机制、调整文档样式等功能。
总的来说,FastAPI 对 OpenAPI 和 Swagger 的支持使得开发者能够更轻松地设计、实现和文档化他们的 API,同时也提高了 API 的可发现性和可用性。
问: 请说明一下FastAPI是如何支持异步IO的?
FastAPI 是一个基于 Python 的现代 Web 开发框架,它利用了 Python 的异步 I/O 功能来实现高性能的网络应用程序。以下是如何 FastAPI 支持异步 I/O 的简要说明:
-
基于
asyncio
: FastAPI 建立在asyncio
模块之上,这是 Python 内置的标准库之一,用于编写单线程并发程序。 -
定义异步路径操作函数: 在 FastAPI 中,你可以使用
async def
定义你的路径操作函数,使其成为协程(coroutine)。这允许它们在事件循环中非阻塞地运行,并等待 I/O 操作完成,而不会阻止其他任务的执行。 -
依赖注入和异步支持: FastAPI 的依赖注入系统也支持异步依赖。这意味着你可以在需要时异步地初始化或获取依赖项。
-
Starlette 库: FastAPI 实际上是构建在 Starlette 微框架之上的,而 Starlette 本身提供了对异步处理的支持。因此,FastAPI 可以利用 Starlette 的异步中间件、路由和其他功能。
-
性能优化: 使用异步编程可以显著提高系统的性能,特别是在高并发场景下,如处理大量的数据库查询、文件读写或其他 I/O 密集型任务。
-
并行性与扩展性: 异步编程使得 FastAPI 能够更好地处理多个请求,因为不同的请求可以在同一时间被处理,而不必按照顺序逐个完成。这有助于提高服务器资源的利用率,并为高负载下的扩展提供了可能。
-
兼容性: 尽管 FastAPI 鼓励使用异步编程,但它同时也支持同步代码。如果你有已有的同步代码或者不希望进行异步编程,你可以直接在 FastAPI 中使用同步代码,但可能会牺牲一些性能优势。
综上所述,FastAPI 通过其设计和底层使用的库,提供了全面的异步 I/O 支持,使开发者能够构建出高效、可扩展的 Web 应用程序。
问: 请详细介绍一下FastAPI是如何处理HTTP请求的?
FastAPI 是一个基于 Python 的现代 Web 开发框架,它通过高效和直观的方式处理 HTTP 请求。以下是 FastAPI 处理 HTTP 请求的详细步骤:
-
路由解析:
- 当用户向 FastAPI 应用程序发送一个请求时,该请求首先被传送到 Starlette(FastAPI 基于的一个轻量级 ASGI 微框架)的路由器。
- 路由器根据请求的 URL 和方法(如 GET、POST 等)来确定哪个路径操作函数应该被调用来处理这个请求。
-
依赖注入:
- 在调用路径操作函数之前,FastAPI 会检查是否有定义在函数参数上的任何依赖项(使用
Depends
装饰器)。 - 如果存在依赖项,FastAPI 会实例化或获取这些依赖项,并将它们作为参数传递给路径操作函数。
- 在调用路径操作函数之前,FastAPI 会检查是否有定义在函数参数上的任何依赖项(使用
-
异步处理:
- 路径操作函数通常以
async def
定义,使其成为协程。这意味着当函数内部有 I/O 密集型操作时,可以利用 asyncio 模块进行非阻塞等待。 - 这种异步编程模型允许 FastAPI 同时处理多个请求,从而提高服务器性能。
- 路径操作函数通常以
-
请求数据解析:
- FastAPI 使用 Pydantic 库来解析和验证请求体中的数据。
- 根据你如何定义你的路径操作函数的输入参数,FastAPI 可以自动地从 JSON、表单数据、查询参数等来源提取数据并将其转换为相应的 Python 类型。
-
业务逻辑处理:
- 路径操作函数包含了实际的业务逻辑,即对请求数据进行处理并生成响应内容。
- 函数内的代码可以包含数据库查询、其他 API 调用、计算或其他需要的操作。
-
异常处理:
- 如果路径操作函数中抛出异常(包括自定义异常和预定义的 HTTP 异常),FastAPI 将捕获这些异常并返回适当的 HTTP 错误响应。
- 这个特性使得开发者能够轻松地控制错误处理流程,而不需要编写复杂的错误处理代码。
-
响应构建:
- 当路径操作函数执行完毕后,其返回值会被用于构建响应。
- FastAPI 自动将返回的数据序列化为 JSON 或其他格式,并设置正确的 Content-Type 标头。
-
响应发送:
- 最后,响应被发送回客户端,完成一次完整的 HTTP 请求-响应周期。
-
中间件支持:
- FastAPI 支持中间件,这是一些可以在请求到达路径操作函数之前或之后运行的可插拔功能组件。
- 中间件可以用于添加跨域支持、身份验证、日志记录等功能。
通过这些步骤,FastAPI 提供了一个灵活且高效的机制来处理 HTTP 请求,同时保持了清晰和简洁的代码结构。
问: 请详细描述一下FastAPI是如何处理请求/响应头的?
在 FastAPI 中,处理请求和响应头是通过以下方式实现的:
-
获取请求头:
- 要访问请求头中的信息,FastAPI 提供了
Request
类。你可以将它作为路径操作函数的一个参数(使用Depends()
装饰器)来注入一个请求对象。 - 一旦你有了这个请求对象,就可以通过其属性(如
.headers
)来访问原始请求头字典。例如,要获取名为 “User-Agent” 的请求头,可以使用如下代码:request.headers.get("User-Agent")
。
- 要访问请求头中的信息,FastAPI 提供了
-
设置响应头:
- 在路径操作函数中,你可以直接返回一个包含额外响应头的对象。这种对象可以是一个简单的 Python 字典或
HTTPResponse
对象。 - 为了更方便地管理响应头,FastAPI 还提供了
Response
类,它可以用来创建带有自定义头部的 HTTP 响应。Response
类接受两个主要参数:要返回的数据和一组头部关键字参数。 - 例如,要返回一个具有自定义 “Cache-Control” 头部的 JSON 响应,可以这样做:
from fastapi.responses import Response def my_endpoint(): data = {"message": "Hello, world!"} headers = {"Cache-Control": "max-age=60"} return Response(content=data, media_type="application/json", headers=headers)
- 在路径操作函数中,你可以直接返回一个包含额外响应头的对象。这种对象可以是一个简单的 Python 字典或
-
自动转换类型:
- 当你在路径操作函数签名中声明一个类型为
Header
的参数时,FastAPI 会自动从请求头中提取该字段,并将其转换为你指定的类型。 - 如果该字段不存在于请求头中,FastAPI 将根据你的配置抛出异常或提供默认值。
- 示例:
from fastapi import Header def my_endpoint(x_token: str = Header(...)): # 使用 x_token 变量... pass
- 当你在路径操作函数签名中声明一个类型为
-
验证和转换:
- 和其他类型的输入一样,FastAPI 允许对请求头进行验证和转换。这可以通过使用 Pydantic 模型或标准库类型来进行。
- 例如,如果你希望确保 “Content-Type” 请求头总是存在的,并且它的值符合某种模式,你可以这样做:
from pydantic import BaseModel from fastapi import Header class ContentType(BaseModel): value: constr(regex=r"^application/json$") def my_endpoint(content_type: ContentType = Header(...)): # 使用 content_type.value 变量... pass
总之,FastAPI 提供了一种直观的方式来处理请求和响应头。开发者可以直接访问请求头、添加自定义响应头,并利用类型提示和模型验证来确保数据的正确性。
问: 请阐述一下FastAPI是如何处理文件上传的?
在 FastAPI 中,处理文件上传是通过 UploadFile
类实现的。以下是使用 FastAPI 处理文件上传的基本步骤:
-
导入所需模块:
- 首先,在你的代码中导入所需的模块和类。
from fastapi import File, UploadFile
- 首先,在你的代码中导入所需的模块和类。
-
定义路径操作函数:
- 创建一个路径操作函数,并在其参数列表中添加一个类型为
UploadFile
的参数。这个参数将用来接收上传的文件。@app.post("/upload-file/") async def upload_file(file: UploadFile): ...
- 创建一个路径操作函数,并在其参数列表中添加一个类型为
-
读取文件内容:
- 在路径操作函数内部,你可以访问
UploadFile
对象的.file
属性来获取文件对象(通常是 SpooledTemporaryFile 或 BytesIO)。 - 使用
.read()
方法可以读取文件内容。请注意,这会消耗内存,因此对于大文件,你可能需要分块读取或使用其他策略。file_content = await file.read()
- 在路径操作函数内部,你可以访问
-
保存到本地文件系统:
- 如果你想将文件保存到本地文件系统,可以使用 Python 的内置函数
open()
来创建一个新的文件,并使用write()
函数将文件内容写入新文件。with open("new_filename.txt", "wb") as new_file: new_file.write(file_content)
- 如果你想将文件保存到本地文件系统,可以使用 Python 的内置函数
-
清理资源:
- 为了确保释放临时文件所占用的资源,你需要调用
UploadFile
对象的.close()
方法。await file.close()
- 为了确保释放临时文件所占用的资源,你需要调用
-
错误处理:
- 考虑到文件上传可能会出现各种错误,你应该包含适当的异常处理代码。例如,检查文件大小、类型等。
-
返回响应:
- 最后,你可以根据业务需求返回适当的响应给客户端,告知他们文件上传的结果。
除了以上基本步骤外,FastAPI 还允许你设置文件上传的限制,如最大大小、允许的文件类型等。这些配置可以通过使用 File
类型的额外参数进行指定。此外,还可以结合使用 Pydantic 模型对上传的文件进行验证。
总的来说,FastAPI 提供了一个直观且功能丰富的机制来处理文件上传,使开发者能够轻松地构建支持文件上传的 Web 应用程序。
问: 请简述一下FastAPI是如何处理Session和Cookies的?
在 FastAPI 中,处理会话(Session)和 Cookies 是通过 Starlette 库提供的功能实现的。以下是 FastAPI 处理 Session 和 Cookies 的简要概述:
-
Cookies:
- 设置响应中的 Cookies:你可以使用
Response
类的.set_cookie()
方法来设置一个或多个 Cookies。这个方法接受 cookie 名称、值和其他可选参数,如过期时间、路径等。from fastapi import Response @app.get("/cookie/") async def set_cookie(response: Response): response.set_cookie(key="my_cookie", value="the_value")
- 设置响应中的 Cookies:你可以使用
-
读取请求中的 Cookies:
- 从请求中获取 Cookies:FastAPI 会自动将请求头中的 “Cookie” 字段解析为字典,并将其作为
Request
对象的.cookies
属性提供。你可以在路径操作函数中访问此属性来读取请求中的 Cookies。from fastapi import Request @app.get("/read-cookie/") async def read_cookie(request: Request): my_cookie = request.cookies.get("my_cookie") ...
- 从请求中获取 Cookies:FastAPI 会自动将请求头中的 “Cookie” 字段解析为字典,并将其作为
-
Session:
- 在 FastAPI 中,没有内置的 Session 支持。但是,你可以通过集成第三方库,如
itsdangerous
或secure-cookie-session
来实现会话管理。 - 使用这些库,你可以创建一个自定义中间件来处理会话数据的存储和检索。通常,这包括在请求时加载会话数据,以及在响应时更新和保存会话数据。
- 在 FastAPI 中,没有内置的 Session 支持。但是,你可以通过集成第三方库,如
-
JWT:
- 虽然 FastAPI 没有直接支持基于 JWT(JSON Web Tokens)的会话管理,但可以结合其他库,如
PyJWT
来实现 JWT 验证和授权。JWT 可以用于无状态的会话管理,在每个请求中携带令牌并在服务器端验证它。
- 虽然 FastAPI 没有直接支持基于 JWT(JSON Web Tokens)的会话管理,但可以结合其他库,如
-
安全提示:
- 请注意,无论使用哪种方式处理会话和 Cookies,都应确保遵循最佳的安全实践,如加密敏感信息、限制会话有效期等。
总之,FastAPI 提供了基本的 Cookie 设置和读取功能,而对于更复杂的会话管理,需要开发者结合外部库进行实现。
问: 请解释一下FastAPI是如何处理HTTP重定向的?
在 FastAPI 中,处理 HTTP 重定向是通过 RedirectResponse
类实现的。以下是使用 FastAPI 处理 HTTP 重定向的基本步骤:
-
导入所需模块:
- 首先,在你的代码中导入所需的模块和类。
from fastapi import RedirectResponse
- 首先,在你的代码中导入所需的模块和类。
-
创建重定向响应:
- 在路径操作函数内部,你可以创建一个
RedirectResponse
对象,并将你要重定向到的 URL 作为参数传递给它。@app.get("/redirect-me/") async def redirect_me(): url = "https://example.com/new-location" return RedirectResponse(url)
- 在路径操作函数内部,你可以创建一个
-
设置状态码(可选):
- 默认情况下,
RedirectResponse
使用 HTTP 状态码 307 (Temporary Redirect)。如果你想使用其他状态码(如 301, 302),可以通过在创建RedirectResponse
时提供额外的status_code
参数来指定。return RedirectResponse(url, status_code=status.HTTP_301_MOVED_PERMANENTLY)
- 默认情况下,
-
添加额外头部信息(可选):
- 如果你需要向重定向响应添加自定义头部信息,可以将它们作为关键字参数传递给
RedirectResponse
构造函数。headers = {"X-Custom-Header": "Some value"} return RedirectResponse(url, headers=headers)
- 如果你需要向重定向响应添加自定义头部信息,可以将它们作为关键字参数传递给
-
返回响应:
- 当你从路径操作函数返回
RedirectResponse
时,FastAPI 将自动发送适当的 HTTP 响应给客户端,指示他们重新定位到新的 URL。
- 当你从路径操作函数返回
请注意,如果需要处理多个重定向或更复杂的逻辑,可能需要编写自定义中间件或扩展 FastAPI 的默认行为。另外,为了确保安全性和用户体验,应该谨慎使用重定向,并遵循最佳实践,例如避免无限循环、保护敏感数据等。
问: 请说明一下FastAPI是如何处理异常和错误的?
在 FastAPI 中,处理异常和错误是通过使用装饰器和定义自定义异常类实现的。以下是 FastAPI 处理异常和错误的基本步骤:
-
创建自定义异常类:
- 如果你需要捕获特定类型的错误,可以创建一个继承自
Exception
的自定义异常类。class MyCustomError(Exception): pass
- 如果你需要捕获特定类型的错误,可以创建一个继承自
-
抛出异常:
- 在路径操作函数中,当发生错误或不符合预期的情况时,你可以抛出相应的异常。这可以是内置的异常类型(如
ValueError
),也可以是你自己定义的异常类。@app.get("/my-endpoint/") async def my_endpoint(): if some_condition: raise MyCustomError("This is a custom error") ...
- 在路径操作函数中,当发生错误或不符合预期的情况时,你可以抛出相应的异常。这可以是内置的异常类型(如
-
全局异常处理:
- 使用
@app.exception_handler()
装饰器来定义全局异常处理器。这个装饰器接受一个异常类作为参数,并返回一个处理该异常的函数。在这个函数内部,你可以决定如何响应给客户端。@app.exception_handler(MyCustomError) async def handle_my_custom_error(request: Request, exc: MyCustomError): return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content={"error": str(exc)}, )
- 使用
-
路由级别的异常处理:
- 如果你想为特定的路由或一组路由提供单独的异常处理逻辑,可以使用
FastAPI.include_router()
函数的exception_handlers
参数。这个参数应该是一个字典,其中键是异常类,值是处理这些异常的函数。router = APIRouter() @router.get("/my-route/") async def my_route(): ... @router.exception_handler(MyCustomError) async def handle_my_custom_error_for_this_route(request: Request, exc: MyCustomError): ... app.include_router(router, exception_handlers={MyCustomError: handle_my_custom_error_for_this_route})
- 如果你想为特定的路由或一组路由提供单独的异常处理逻辑,可以使用
-
标准 HTTP 异常:
- 对于常见的 HTTP 错误状态码,FastAPI 提供了预定义的异常类,如
HTTPException
。你可以直接使用这些异常类来快速引发标准的 HTTP 错误。from fastapi import HTTPException @app.get("/standard-error/") async def standard_error(): raise HTTPException(status_code=404, detail="Not found")
- 对于常见的 HTTP 错误状态码,FastAPI 提供了预定义的异常类,如
-
其他异常处理:
- 除了上述方法外,你还可以使用 Python 的标准异常处理机制(如
try/except
块)来捕获并处理异常。
- 除了上述方法外,你还可以使用 Python 的标准异常处理机制(如
总之,FastAPI 提供了一个灵活且可扩展的异常处理系统,允许开发者轻松地定制错误处理逻辑,以满足应用程序的需求。