Python WEB框架之FastAPI
今天想记录一下最近项目上一直在用的Python框架——FastAPI。
个人认为,FastAPI是我目前接触到的Python最好用的WEB框架,没有之一。
之前也使用过像Django、Flask等框架,但是Django就用起来太重了,各种功能都糅杂在一起;Flask 框架虽说简单,但又只是单线程需要自己改造才支持多并发。
FastAPI貌似结合弥补了Flask 框架的缺陷,如果你想要快速搭建一个WEB服务,用FastAPI准没错。
OK,开始今天的笔记。
一、安装FastAPI
pip install fastapi uvicorn python-multipart
二、示例代码
from fastapi import FastAPI
import uvicornapp = FastAPI()@app.get("/")
def index():return "Hello World"if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)
运行起来之后,您应该会看到下面的画面:
浏览器访问你的ip地址加端口号,应该就能看到“Hello World”。
三、接受请求参数
1、直接通过参数名接受,参数名即传参的名称。
@app.get("/info")
def handle_info(name, age):return f"Hello World, {name}, {age}"
这种方式必须接受name和age参数,如果缺少参数则会看到以下错误:
适用于GET请求且参数固定的情况,并且可以省去自己验证必要参数的步骤。
正常传递后则不会发生错误:
2、使用Request对象传参
1)GET请求
from fastapi import FastAPI, Request@app.get("/request")
def handle_info(params: Request):return params.query_params
从fastapi库导入Request对象,使用Request对象作为接受参数,Request对象会把所有的参数都收集到query_params
属性当中。
2)POST请求
@app.post("/request")
async def handle_info(params: Request):form = dict(await params.form())return form
需要注意的是这里需要将使用async
和await
关键字,然后强转为 dict
类型,就可以愉快的使用啦。
3)文件上传
# 图片批量上传
@app.post('/upload')
async def upload_file(params: Request, files: List[UploadFile] = File(...)):form = dict(await params.form())save_files = []for file in files:temp_arr = file.filename.split(".")suffix = temp_arr[len(temp_arr) - 1]file_name = f"img_{datetime.now().strftime('%Y%m%d%H%M%S%f')}.{suffix}"with open(file_name, "wb") as f:content = await file.read() # 读取上传文件的内容f.write(content) # 将内容写入文件save_files.append(file_name)return {"code": 200,"data": {"params": form,"save_files": save_files}}
实例为图片批量上传示例,使用Request对象进行接收,同时上传的文件也会被映射到files参数中。
可通过file.read()
读取文件内容,file.filename
可拿到上传的文件名。
单文件上传,个人觉得可以沿用。
前端上传文件示例代码:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><input type="file" name="" id="file" multiple onchange="upload()"><div id="output"></div>
</body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type="text/javascript">let upload = () => {let el_file = document.querySelector("#file")let output = document.querySelector("#output")const form = new FormData();for (let i = 0; i < el_file.files.length; i++) {form.append('files', el_file.files[i]);}form.append("name", "zhangsan");form.append("age", 20);this.uploadStage = true;axios.post('http://127.0.0.1:8000/upload', form, {headers: { 'Content-Type': 'multipart/form-data' }}).then(res => {output.innerHTML = JSON.stringify(res.data)}).catch(err => {output.innerHTML = JSON.stringify(err)});}
</script>
</html>
示例结果:
四、跨域设定
from starlette.middleware.cors import CORSMiddleware
# 添加CORS中间件
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],
)
*
号部分可自由配置。
五、指定静态资源目录
from fastapi.staticfiles import StaticFiles
app.mount("/static", StaticFiles(directory="static"), name="static_resources")
将static
目录挂载为静态目录,当访问 /static
时直接返回该文件内容。
把上述文件上传的示例文件index.html
放到static
文件夹下,则可直接通过 /static/index.html
访问。
六、返回文件
from starlette.responses import FileResponse@app.get("/index")
def home():return FileResponse("static/index.html")
可通过FileResponse类返回指定文件的内容。用于做图片的预览、文件下载等功能。
现在也可以通过 /index
访问到 static/index.html
文件了。
以上,就是本次用到的fastapi 框架的相关内容。
相信以上知识已经足够解决日常的开发问题,希望看到的小伙伴不迷路。
欢迎大家留言探讨。
最后,奉上完整示例代码:
from datetime import datetime
from typing import Listfrom fastapi import FastAPI, Request, UploadFile, File
import uvicorn
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import FileResponse
from starlette.staticfiles import StaticFilesapp = FastAPI()
# 添加CORS中间件
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],
)app.mount("/static", StaticFiles(directory="static"), name="static_resources")@app.get("/")
def index():return "Hello World"@app.get("/index")
def home():return FileResponse("static/index.html")@app.get("/info")
def handle_info(name, age):return f"Hello World, {name}, {age}"@app.post("/request")
def handle_info(params: Request):return params.query_params@app.post("/request")
async def handle_info1(params: Request):form = dict(await params.form())return form# 图片批量上传
@app.post('/upload')
async def upload_file(params: Request, files: List[UploadFile] = File(...)):form = dict(await params.form())save_files = []for file in files:temp_arr = file.filename.split(".")suffix = temp_arr[len(temp_arr) - 1]file_name = f"img_{datetime.now().strftime('%Y%m%d%H%M%S%f')}.{suffix}"with open(file_name, "wb") as f:content = await file.read() # 读取上传文件的内容f.write(content) # 将内容写入文件save_files.append(file_name)return {"code": 200,"data": {"params": form,"save_files": save_files}}if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)