官文敬上:虽然看不明白
官方文档
安装框架
pip install fastapi -- web框架
pip install uvicorn --基于高并发的模块,fastapi启动依赖于它
写一个最简单的接口
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get('/') #一个get请求
async def root():
return {'hello':'World'} #返回值
if __name__ == '__main__':
uvicorn.run(app,host='127.0.0.1',port=8000) #可以直接运行此脚本
#uvicorn polls:app --reload
#uvicorn 文件名:实例名 --在代码改变后重启服务器,只能在开发的时候使用
#命令行启动必须进入该文件的根路径
Fastapi自带接口文档
启动项目后访问127.0.0.1:8000/docs
127.0.0.1:8000/redoc
fastapi使用模板渲染
pip install jinja2 -- 安装模板渲染模块
import uvicorn
from fastapi import FastAPI
from starlette.requests import Request
from starlette.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory='../templates') #模板路径
@app.get('/')
async def root(request:Request): #必须有这个参数,拿不到数据
return templates.TemplateResponse('index.html',{'request':request,'hello':'测试数据'})
#渲染的模板名, 后面的hello为模板的变量名,后面是数据
if __name__ == '__main__':
uvicorn.run(app, host='127.0.0.1', port=8000)
# uvicorn polls:app --reload
# uvicorn 文件名:实例名 --在代码改变后重启服务器,只能在开发的时候使用
#测试渲染模板index.html中
Title
{{ hello }}
#启动运行项目.可以看到渲染成功的页面
路径参数的传递
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get('/{user_id}/')
async def root(user_id):
return user_id
if __name__ == '__main__':
uvicorn.run(app, host='127.0.0.1', port=8000)
#请求http://127.0.0.1:8000/12555/ 可以看到12555
----------------------------------------------------------------------------
#预定传递路径参数(也就是路径参数必须是我们提前预设的值)
import uvicorn
from enum import Enum
from fastapi import FastAPI
app = FastAPI()
class ModelName(str,Enum): #意思就是底下{name}中的值必须为我们这个类中定义的三个属性值
alexent = 'alexnet'
resnet = 'resnt' #比如,我们定义resnt,那么必须在url中输入resnt才可以执行进视图函数
lenet = 'lenet' #如果输入为resnet,则不可以进入视图函数
@app.get('/api/{name}/') #如果我们name中的值不是我们上面定义好的属性值,那么返回错误json
async def root(name: ModelName):
if name == ModelName.alexent: #这种方式检查路径参数比较优雅
return {'mes':'alexent'}
if name.value == 'lenet': #这种方式也可以取到路径参数中的值
return {'name':name,'mes':'lenet'}
return {"name":name,'mes':'resnet'}
---------------------------------------------------------------------------------
#路径参数中包含路径参数(例如:api/1/2/3)
@app.get('/api/{name:path}/')
async def root(name):
return {'mes':name}
#浏览器中随便输入,可接受多个路径参数
参数传递的类型检验(校验)
#python3.6中已经支持声明变量的类型
@app.get('/api/{user_id}/')
async def root(user_id: bool): #这种情况下user_id被声明为bool类型,如果传递别的参数,那就type error
return user_id
查询参数(中间带?的参数)
import uvicorn
from fastapi import FastAPI
app = FastAPI()
fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]
@app.get("/items/")
async def read_item(page:int=0, size:int=10): #当然这里不声明的话,在切片的时候声明也是可以的
return fake_items_db[page : page + size]
#默认查10条,从page条开始查
#请求:127.0.0.1:8000/items/?page=1
注意:如果请求127.0.0.1:8000/items/ 相当于执行视图函数中参数的默认值
输出为:
[
{
item_name: "Bar"
},
{
item_name: "Baz"
}
]
路径参数和查询参数配合使用
from typing import Optional
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/{name}/")
async def read_item(name:str,age:Optional[str] = None): #官文中这样使用(可以理解为是可选参数)
if age:
return {'name':name,'age':age}
return name
POST请求拿raw(json)数据
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel): #必须先定义json参数的模型
name: str
description: Optional[str] = None #非必选参数
price: float
tax: Optional[float] = None #非必选参数
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
输出如下:
@app.post("/items/")
async def create_item(item: Item):
print(item.dict()) #转化字典
item_dict = item.dict() #可以通过.对象的方法来获取值
if item.tax:
price_with_tax = item.price + item.tax
item_dict.update({"price_with_tax": price_with_tax})
return item_dict
POST请求拿from(表单)数据
pip install python-multipart #装模块
from fastapi import FastAPI, Form
app = FastAPI()
@app.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)): #可以拿到表单数据
return {"username": username,"passwod":password}
如下:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/") #这种方式是在表单中提交,需要前端吧文件转字节码
async def create_file(file: bytes = File(...)):
print(file)
return {"file_size": file}
#注意:这种方式是吧文件存在内存中,适合小文件传输
表单中文件上传
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def upload_file(file: UploadFile = File(...)):
content = await file.read() #一次性读取,文件太大服务器就得崩溃
with open(f'{file.filename}','wb') as f:
f.write(content)
return {"filename": file.filename,'content_type':file.content_type}
#注意:这种方式只适合小文件上传
--------------------------------------------------------------------------------
#大文件上传
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def upload_file(file: UploadFile = File(...)):
with open(f'{file.filename}','wb') as f:
for i in iter(lambda : file.file.read(512),b''):
f.write(i)
f.close()
return {"filename": file.filename,'content_type':file.content_type}
UploadFile
UploadFile 具有以下属性:
filename:str具有上载的原始文件名的A (例如myimage.jpg)。
content_type:str具有内容类型(MIME类型/媒体类型)(例如image/jpeg)的A。
file:一个SpooledTemporaryFile(类似文件的对象)。这是实际的Python文件,您可以将其直接传递给需要“类文件”对象的其他函数或库。
UploadFile具有以下async方法。它们都调用了下面的相应文件方法(使用internal SpooledTemporaryFile)。
write(data):将data(str或bytes)写入文件。
read(size):读取size(int)个文件的字节/字符。
seek(offset):转到文件中的字节位置offset(int)。
例如,await myfile.seek(0)将转到文件的开头。
如果您运行await myfile.read()一次然后需要再次读取内容,则此功能特别有用。
close():关闭文件。
批量上传文件
from typing import List
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/file/")
async def create_files(files: List[bytes] = File(...)):
return {"file_sizes": [len(file) for file in files]}
#注意:这里必须前端表单中必须为file类型,而不是上面的text类型
@app.post("/files/")
async def create_upload_files(files: List[UploadFile] = File(...)):
return {"filenames": [file.filename for file in files]}
#注意:表单中包含多个files文件,推荐使用这种方法
----------------------------------------------------------------------------------
#大文件批量上传
@app.post("/files/")
async def create_upload_files(files: List[UploadFile] = File(...)):
for file in files:
with open(f'{file.filename}','wb') as f:
for i in iter(lambda : file.file.read(512),b''):
f.write(i)
f.close()
return {"filenames": [file.filename for file in files]}
表单中text与file类型配合使用
from fastapi import FastAPI, File, Form, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(
file: bytes = File(...), fileb: UploadFile = File(...), token: str = Form(...)
):
return {
"file_size": len(file),
"token": token,
"fileb_content_type": fileb.content_type,
}
配置跨域资源共享
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-表示跨域请求应支持cookie。默认为False。
expose_headers-指出应该使浏览器可以访问的任何响应头。默认为[]。
max_age-设置浏览器缓存CORS响应的最长时间(以秒为单位)。默认为600。
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = [
"*",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
部署fastapi
利用进程管理gunicorn
在 FastAPI 中,可以通过 StreamingResponse 类来实现流式响应。StreamingResponse 类需要传入一个生成器函数,该函数会在响应被发送到客户端时逐步生成响应内容。
以下是一个示例代码,演示如何使用 StreamingResponse 类返回流式响应:
from fastapi import FastAPI, Response
from fastapi.responses import StreamingResponse
import time
app = FastAPI()
def generate():
for i in range(10):
yield f"streaming response {i}\n"
time.sleep(1)
@app.get("/stream")
async def stream():
return StreamingResponse(generate())
在上面的示例中,generate 函数是一个生成器函数,它会逐步生成响应内容。stream 函数使用 StreamingResponse 类来返回流式响应,generate 函数作为参数传入 StreamingResponse 类的构造函数中。
当客户端请求 /stream 路径时,stream 函数会返回一个 StreamingResponse 对象,该对象会逐步生成响应内容并发送到客户端。客户端可以通过读取响应内容来逐步接收数据。
需要注意的是,由于 StreamingResponse 类会逐步生成响应内容,因此在生成器函数中需要适当地添加延时,以便客户端有足够的时间来接收数据。