赞
踩
FastAPI是一个用于构建API的现代、快速(高性能)的web框架。它基于Python 3.6+,并利用了Python的类型提示。FastAPI的特点包括:
高性能:FastAPI与NodeJS和Go具有可比的出色性能,这主要归功于它建立在Starlette和Pydantic之上,并利用异步编程。
高效编码:它能够提高功能开发速度约200%至300%,同时减少约40%的人为(开发者)导致的错误。
智能与易用:FastAPI提供了极佳的编辑器支持,处处皆可自动补全,减少了调试时间。此外,它设计的易于使用和学习,使得阅读文档的时间更短。
自动文档生成:FastAPI能够自动生成交互式API文档,支持Swagger UI和ReDoc,使得API的理解和测试更加直观。
广泛适用:FastAPI适用于多种场景,包括构建RESTful API、WebSocket实时通信、创建Web应用以及开发微服务。
在FastAPI中,Starlette和Pydantic各自扮演了重要的角色。
Starlette是一个轻量级的ASGI(异步服务器网关接口)框架/工具包。它进一步封装了web请求,使得开发者能够更方便地使用。FastAPI建立在Starlette框架之上,Starlette的轻量级和可扩展性为FastAPI提供了坚实的基础。这种结构使得FastAPI能够快速且高性能地处理web请求,是当今可用的最快的Web框架之一。
另一方面,Pydantic是一个非常流行的Python序列化和反序列化库。它提供了数据模型的定义和验证,使得开发者能够方便地处理请求和响应的数据。FastAPI内置了Pydantic,因此可以方便地利用Pydantic来操作请求和响应的数据。在处理请求数据时,Pydantic可以对数据进行验证和转换,并返回处理后的结果。此外,FastAPI还提供了一些常用的Pydantic扩展,例如fastapi-utils(提供了一些常用的请求和响应处理函数)、fastapi-pagination(提供了分页处理的功能)、fastapi-jwt-auth(提供了JWT认证的功能)等,这些扩展进一步增强了FastAPI的功能性和便利性。
总的来说,Starlette和Pydantic在FastAPI中各自发挥了重要的作用,Starlette提供了基础的web请求处理框架,而Pydantic则负责数据的序列化和反序列化,以及数据的验证和转换。这使得FastAPI能够成为一个功能强大、易于使用且高性能的web框架
- # 模拟http的请求和响应格式
-
- import json
- import socket
- import re
-
-
- class Request:
- def __init__(self):
- self.header = {}
- self.body = {}
- self.url = None
- self.param = {}
- self.request_type = None
- self.content = None
-
- def load(self, data):
- self.content = data.decode()
- print(f"收到:{self.content}")
- first, *headers, body = self.content.split("\n")
- self.request_type, url, *_ = first.split()
- for header in headers:
- header = header.strip("\r")
- if header:
- key, *values = header.split(":")
- self.header[key] = ":".join(values)
- if "?" in url:
- path_url, temp = url.split("?")
- params = temp.split("&")
- for param in params:
- key, value = param.split("=")
- self.param[key] = value
- else:
- path_url = url
-
- self.url = self.header.get("Host") + path_url
-
- def __str__(self):
- return self.content
-
-
- class Response:
- def __init__(self):
- self.status = 200
- self.message = "ok"
- self.header = {
- 'content-type': "application/json"
- }
- self.body = {"name": "xiaomi", "age": 14}
-
- def __str__(self):
- response = 'HTTP/1.1 {status} {message}\r\n{header}\r\n{body}'
- header = ""
- for key, value in self.header.items():
- header += f"{key}: {value}\r\n"
- message = response.format(status=self.status, message=self.message, header=header, body=json.dumps(self.body))
- print(f"发送:{message}")
- return message
-
-
- class Service:
- def __init__(self, host, port):
- self.host = host
- self.port = port
- self.sock = socket.socket()
- self.reqeust = Request()
- self.response = Response()
- self.running = True
-
- def read(self, conn):
- data = conn.recv(1024)
- self.reqeust.load(data)
-
- def send(self, conn):
- conn.send(str(self.response).encode())
-
- def run(self):
- self.sock.bind((self.host, self.port))
- self.sock.listen(5)
- while self.running:
- conn, addr = self.sock.accept()
- print(f"客户端链接:{addr}")
- self.read(conn)
- self.send(conn)
- self.sock.close()
-
-
- if __name__ == '__main__':
- s = Service("127.0.0.1", 8000)
- s.run()
前后端不分离
前后端分离
前后端不分离: 浏览器访问网址时,后端服务器从数据库中查询到数据通过模板页面构造成一个html文件返回给浏览器
前后端分离: 浏览器访问网址时,前端服务器(vue)先返回静态的资源(html、css、js),浏览器在通过前端服务器请求数据,前端服务器收到请求之后访问后端服务拿到数据返回给浏览器
RESTful规范是HTTP协议的一种规范化设计风格,它代表了“表征性状态转移”(Representational State Transfer)的缩写。RESTful规范的核心思想是将网络资源视为一系列可以通过统一接口进行操作的实体,它强调资源的表示、状态转移以及客户端与服务器之间的交互。
RESTful规范主要具有以下几个核心原则:
资源:在RESTful架构中,所有事物都被视为资源,资源由URI(统一资源标识符)来标识。
无状态:服务器不会在请求之间保留任何客户端的上下文信息,即每个请求都必须包含足够的信息以便服务器理解并处理。
统一的接口:RESTful架构通过定义一组预定义的HTTP方法(如GET、POST、PUT、DELETE等)来对资源进行操作,这些方法分别对应着资源的获取、创建、更新和删除等操作。
分层系统:RESTful架构允许将系统划分为多个层次,每个层次对下层提供服务,同时隐藏其内部实现细节。
客户端-服务器架构:RESTful架构将系统划分为客户端和服务器两个部分,客户端负责用户交互和显示,服务器负责存储和管理资源。
此外,RESTful规范还涉及其他一些细节,如使用HTTPS进行交互以保证数据安全,使用名词(可复数)来表示资源,以及通过URL参数进行搜索、过滤和排序等。
RESTful规范的优势在于它使得Web服务更加简洁、高效、可扩展和可维护。它降低了客户端和服务器之间的耦合度,提高了系统的可移植性和可见性。同时,RESTful架构的灵活性使得它可以与现有的技术和基础设施进行集成,为开发人员提供了更多的选择和可能性。
请求方法 | 请求地址 | 后端操作 |
---|---|---|
POST | /student/ | 增加学生 |
GET | /student/ | 获取所有学生 |
GET | /student/1 | 获取id为1的学生 |
PUT | /student/1 | 修改id为1的学生 |
DELETE | /student/1 | 删除id为1的学生 |
接口文档地址: /host:port/docs
完整代码地址:
链接:https://pan.baidu.com/s/1F1jOj3dlZt42EgdRKyKvjQ?pwd=umtx
提取码:umtx
- """
- app01 为FastApi 的路径参数
- """
-
- from fastapi import APIRouter, Path, Query
- from enum import Enum
-
- app01 = APIRouter()
-
-
- # 1. 基本用法
- @app01.get("/test1")
- def test1():
- return {"name": "test"}
-
-
- # 2.带路径参数
- @app01.get("/test2/{item_id}")
- def test2(item_id: int):
- return {"name": item_id}
-
-
- # 3.预设值枚举类型
- class ModelName(str, Enum):
- first = "first"
- second = "second"
- third = "third"
-
-
- @app01.get("/test3/{item}")
- def test3(item: ModelName):
- return {"name": item}
-
-
- # 4.路径转换
- @app01.get("/test4/{item:path}")
- def test4(item: str):
- return {"item": item}
-
-
- # 访问/app01/test4//home/test.txt能得到正确的路径
-
-
- # 5.数据校验
- @app01.get("/test5/{item}")
- def test5(item: str = Path(title='通过item id获取Item')):
- return {"item": item}
-
'运行
查询字符串是键值对的集合,这些键值对位于 URL 的 ?
之后,并以 &
符号分隔。
- """
- app01 为FastApi 的查询参数
- """
-
- from fastapi import APIRouter, Query
- from typing import Union
- from pydantic import Required
-
-
- app02 = APIRouter()
-
-
- # 1. 必填参数
- @app02.get("/test1")
- def test1(a: int):
- return {"a": a}
-
-
- # 2.可选参数
- @app02.get("/test2")
- def test2(a: Union[str, None] = None):
- return {"a": a}
-
-
- # 3. 默认参数
- @app02.get("/test3")
- def test3(a: int = 1):
- return {"a": a}
-
-
- # 4.数据校验Query
- @app02.get("/test4")
- def test4(item: str = Query(default=Required, min_length=3)):
- return {"item": item}
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。你的 API 几乎总是要发送响应体。但是客户端并不总是需要发送请求体。
- """
- app01 为FastApi 的请求体
- """
-
- from fastapi import APIRouter, Query, Body
- from typing import Union
- from datetime import datetime
- from pydantic import Required, BaseModel, Field, validator
-
-
- app03 = APIRouter()
-
-
- # 1. 基本的数据模型
- class Item(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
- @app03.post("/test1")
- def test1(item: Item):
- return item
-
-
- # 2.模型嵌套
- class Item2(BaseModel):
- name: str
- item: Union[Item, None] = None
-
-
- @app03.post("/test2")
- def test2(item: Item2):
- return item
-
-
- # 3. 请求体字段校验
- class Item3(BaseModel):
- name: str = Field(default="hello", max_length=10, min_length=2)
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
-
- @app03.post("/test3")
- def test3(item: Item3):
- return item
-
-
- # 4. 请求字段函数校验
- class Item4(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- tax: Union[float, None] = None
-
- @validator("price")
- def check_price(cls, price):
- assert 0 < price < 100
- return price
-
-
- @app03.post("/test4")
- def test4(item: Item4):
- return item
-
-
- # 5.多个请求体
- class Book(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
-
-
- class Movie(BaseModel):
- name: str
- description: Union[str, None] = None
- price: float
- release_time: Union[datetime] = None
-
-
- @app03.post("/test5")
- def test5(book: Book, movie: Movie):
- return {"book": book, "movie": movie}
-
-
- # 6. 使用Body修饰请求体
- @app03.post("/test6")
- def test6(item: str = Body(default="hello", max_length=10, min_length=2)):
- return {"item": item}
OAuth2 规范的 "密码流" 模式规定要通过表单字段发送 username
和 password
。该规范要求字段必须命名为 username
和 password
,并通过表单字段发送,不能用 JSON。
声明表单体要显式使用 Form
,否则,FastAPI 会把该参数当作查询参数或请求体(JSON)参数。可在一个路径操作中声明多个 Form
参数,但不能同时声明要接收 JSON 的 Body
字段。因为此时请求体的编码是 application/x-www-form-urlencoded
,不是 application/json
- """
- app01 为FastApi 的表单数据
- """
-
- from fastapi import APIRouter, Form
- # pip install python-multipart
-
- app04 = APIRouter()
-
-
- # 1. 请求体form表单
- @app04.post("/test1")
- def test1(username: str = Form(..., max_length=16, min_length=8, regex='[a-zA-Z]'),
- password: str = Form(..., max_length=16, min_length=8, regex='[0-9]')
- ):
- return {"username": username, "password": password}
'运行
FastApi中使用File和UploadFile进行上传文件
File: 把文件的所有内容都存储在内存里,适用于小型文件。
UploadFile: 存储在内存的文件超出最大上限时,FastAPI 会把文件存入磁盘,更适于处理图像、视频、二进制文件等大型文件
- """
- app01 为FastApi 文件上传
- """
-
- from fastapi import APIRouter, File, UploadFile
- from typing import List
- # pip install python-multipart
-
- app05 = APIRouter()
-
-
- # 1. File文件上传
- @app05.post("/test1")
- def test1(file: bytes = File()):
- file_size = len(file)
- with open("test1.txt", "wb") as f:
- f.write(file)
- return {"file_size": file_size}
-
-
- # 2. UploadFile文件上传
- @app05.post("/test2")
- def test2(file: UploadFile):
- filename = file.filename
- content_type = file.content_type
- file_size = file.size
- headers = file.headers
- with open(filename, "wb") as f:
- for chunk in iter(lambda: file.file.read(1024), b''):
- f.write(chunk)
- return {"filename": filename, "content_type": content_type,
- "headers": headers, "file_size": file_size}
-
-
- # 3. 多文件上传
- @app05.post("/test3")
- def test3(files: List[UploadFile]):
- for file in files:
- with open(file.filename, "wb") as f:
- for chunk in iter(lambda: file.file.read(1024), b''):
- f.write(chunk)
- return {"files": [file.filename for file in files]}
有些情况下我们希望能直接访问Request对象。例如我们在路径操作函数中想获取客户端的IP地址,需要在函数中声明Request类型的参数,FastAPI 就会自动传递 Request 对象给这个参数,我们就可以获取到 Request 对象及其属性信息,例如 header、url、cookie、session 等。
- """
- app01 为FastApi request
- """
-
- from fastapi import APIRouter, Request
-
- app06 = APIRouter()
-
-
- # 1. 获取请求的参数
- @app06.post("/test1")
- def test1(reqeust: Request):
- url = reqeust.url # 完整的url
- base_url = reqeust.base_url # 网址
- host = reqeust.client.host # 客户端地址
- port = reqeust.client.port # 客户端的端口
- cookies = reqeust.cookies # cookie
- method = reqeust.method # 请求方式
- path_params = reqeust.path_params # 路径参数
- query_params = reqeust.query_params # 请求参数
- headers = reqeust.headers # 请求头
- return {"url": url, "base_url": base_url, "host": host,
- "port": port, "cookies": cookies, "method": method,
- "path_params": path_params, "query_params": query_params,
- "headers": headers}
使用路径操作装饰器的 response_model
参数来定义响应模型。
将输出数据转换为response_model中声明的数据类型。
验证数据结构和类型
将输出数据限制为该model定义的
添加到OpenAPI中
在自动文档系统中使用。
- """
- app01 为FastApi response
- """
-
- from fastapi import APIRouter
- from pydantic import BaseModel, EmailStr
- from typing import Union
- # pip install pydantic[email]
-
- app07 = APIRouter()
-
-
- class UserIn(BaseModel):
- username: str
- password: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
- class UserOut(BaseModel):
- username: str
- email: EmailStr
- full_name: Union[str, None] = None
-
-
- # 1. 使用response模型
- @app07.post("/test1", response_model=UserOut)
- def test1(user: UserIn):
- return user
在 Web 开发中,在前后端分离的模式中一般静态资源都是由前端服务提供,但是如果小型项目中或者网站想展示图片资源需可以通过后端服务器中获取静态资源,所以FastApi中支持获取静态资源。
- # 访问静态需要挂载一个目录, 第一个参数表示访问的路径,第二个参数表示实际文件路径。
- app.mount("/static", StaticFiles(directory="static"), name="static")
后端服务出现了异常需要一种友好的方式展示给前端,服务中出现了致命错误记录到日志中或者调试接口时需要将异常详情返回给前端都需要用到异常处理
- """
- app01 为FastApi 异常处理
- """
-
- from fastapi import APIRouter, HTTPException
-
- app08 = APIRouter()
-
-
- # 1.使用HTTPException定义异常信息
- @app08.get("/test1")
- def test1(item_id: int):
- if item_id == 1:
- raise HTTPException(status_code=400, detail="item id 不能为1",
- headers={"X-Error": "params error"})
- return {"item": item_id}
-
-
- # 2.自定义异常处理
- class MyException(Exception):
- def __init__(self, message):
- self.message = message
-
- def __str__(self):
- return str(self.message)
-
-
- @app08.get("/test2")
- def test2(item_id: int):
- if item_id == 1:
- raise MyException("自定义错误item id 不能为1")
- return {"item": item_id}
-
-
- # 2.全局异常处理
- @app08.get("/test3")
- def test3(item_id: int):
- 1/0
- return {"item": item_id}
-
- ----------- 捕获-------
- # 2.自定义异常
- @app.exception_handler(MyException)
- def my_exception_handler(reqeust: Request, exc: MyException):
- return JSONResponse(
- status_code=418,
- content={"message": f"自定义错误: {exc}"}
- )
-
-
- # 3.全局异常处理
- @app.exception_handler(Exception)
- async def http_exception_handler(request: Request, exc: Exception):
- return JSONResponse(content={"message": f"全局错误:{exc}"},
- status_code=500)
依赖是运行必须要满足的条件,在路由中有对请求体的字段设定一个模型,在响应中对响应的模型,而路径参数和查询参数中也能通过依赖项来设置一个模型校验数据,这仅仅是依赖项的其中的一项功能。
依赖注入常用于以下场景:
共享业务逻辑(复用相同的代码逻辑)
共享数据库连接
实现安全、验证、角色权限
等……
- """
- app01 为FastApi 依赖项
- """
-
- from fastapi import APIRouter, Depends
- from fastapi.exceptions import RequestValidationError
- from fastapi.requests import Request
- from typing import List
-
- app09 = APIRouter()
-
-
- # 1.依赖项复用相同的代码
- def common_parameters(name: str = "admin", password: str = "123456"):
- return {"name": name, "password": password}
-
-
- @app09.get("/test1")
- def test1(common: dict = Depends(common_parameters)):
- return common
-
-
- @app09.get("/test2")
- def test2(common: dict = Depends(common_parameters), age: int = 12):
- common.update({"age": age})
- return common
-
-
- # 2.依赖项验证数据
- def user_info(name: str, password: str):
- if 6 < len(name) < 12 and 6 < len(password) < 12:
- return {"name": name, "password": password}
- else:
- raise Exception("name 或password 数据格式错误")
-
-
- @app09.get("/test3")
- def test3(common: dict = Depends(user_info)):
- return common
-
-
- # 3.使用类作为依赖项
- class User:
- def __init__(self, name: str, password: str):
- self.name = name
- self.password = password
-
- def check_validata(self):
- if 6 < len(self.name) < 12 and 6 < len(self.password) < 12:
- pass
- else:
- raise RequestValidationError("name 或password 数据格式错误")
-
- def to_dict(self):
- return {"name": self.name, "password": self.password}
-
-
- @app09.get("/test4")
- def test4(common: User = Depends(User)):
- common.check_validata()
- return common.to_dict()
-
-
- # 4.依赖嵌套
- def student(name: str, age: int):
- return {"name": name, "age": age}
-
-
- def clas(address: str, number: int, stu: student = Depends(student)):
- return {"address": address, "number": number, "stu": stu}
-
-
- @app09.get("/test5")
- def test5(common: dict = Depends(clas)):
- return common
-
-
- # 5. 路径装饰器上使用依赖,依赖不返回
- @app09.get("/test6", dependencies=[Depends(user_info)])
- def test6():
- return {"message": "hello world"}
-
-
- # 6.fastApi中无法修改request数据,可以通过依赖注入
- def get_custom_header(request: Request):
- # 获取头部信息并添加自定义数据
- headers_dict = dict(request.headers)
- headers_dict["X-Custom-Header"] = "CustomValue"
- return headers_dict
-
-
- @app09.get("/test7")
- def test7(custom_headers: dict = Depends(get_custom_header)):
- return custom_headers
"中间件"是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应返回之前工作.
它接收你的应用程序的每一个请求.
然后它可以对这个请求做一些事情或者执行任何需要的代码.
然后它将请求传递给应用程序的其他部分 (通过某种路径操作).
然后它获取应用程序生产的响应 (通过某种路径操作).
它可以对该响应做些什么或者执行任何需要的代码.
然后它返回这个 响应.
- # 1.中间件增加日志记录
- @app.middleware("http")
- def add_log(request: Request, call_next):
- print(f"请求来了: {request}")
- start_time = time.time()
- response = call_next(request)
- print(f"发送响应到客户端: {response}, 耗时:{time.time() - start_time}")
- return response
-
-
- # 2.中间件黑名单
- @app.middleware("http")
- def black_list(request: Request, call_next):
- if "test1" in str(request.url):
- return JSONResponse(status_code=403, content={"message": "您无权访问"})
- response = call_next(request)
- return response
CORS 或者跨域资源共享指浏览器中运行的前端拥有与后端通信的 JavaScript 代码,而后端处于与前端不同的「源」的情况。
allow_origins
- 一个允许跨域请求的源列表。例如 ['https://example.org', 'https://www.example.org']
。你可以使用 ['*']
允许任何源。
allow_origin_regex
- 一个正则表达式字符串,匹配的源允许跨域请求。例如 'https://.*\.example\.org'
。
allow_methods
- 一个允许跨域请求的 HTTP 方法列表。默认为 ['GET']
。你可以使用 ['*']
来允许所有标准方法。
allow_headers
- 一个允许跨域请求的 HTTP 请求头列表。默认为 []
。你可以使用 ['*']
允许所有的请求头。Accept
、Accept-Language
、Content-Language
以及 Content-Type
请求头总是允许 CORS 请求。
allow_credentials
- 指示跨域请求支持 cookies。默认是 False
。另外,允许凭证时 allow_origins
不能设定为 ['*']
,必须指定源。
expose_headers
- 指示可以被浏览器访问的响应头。默认为 []
。
max_age
- 设定浏览器缓存 CORS 响应的最长时间,单位是秒。默认为 600
。
- # 解决跨域问题
- app.add_middleware(
- CORSMiddleware,
- allow_origins="*",
- allow_credentials=True,
- allow_methods=["*"],
- allow_headers=["*"],
- )
你可以在设置 OpenAPI 规范和自动 API 文档 UI 中使用的以下字段:
参数 | 类型 | 描述 |
---|---|---|
title | str | API 的标题。 |
summary | str | API 的简短摘要。 自 OpenAPI 3.1.0、FastAPI 0.99.0 起可用。. |
description | str | API 的简短描述。可以使用Markdown。 |
version | string | API 的版本。这是您自己的应用程序的版本,而不是 OpenAPI 的版本。例如 2.5.0 。 |
terms_of_service | str | API 服务条款的 URL。如果提供,则必须是 URL。 |
contact | dict |
url:指向联系信息的 URL;必须采用 URL 格式; email:联系人/组织的电子邮件地址。必须采用电子邮件地址的格式。 |
license_info | dict | name:必须的 (如果设置了 identifier:一个API的SPDX许可证表达。 The url:用于 API 的许可证的 URL。必须采用 URL 格式。 |
- from fastapi import FastAPI
-
- description = """
- ChimichangApp API helps you do awesome stuff. 声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/863439推荐阅读
相关标签
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。