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 uvicorn
app = 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 List
from fastapi import FastAPI, Request, UploadFile, File
import uvicorn
from starlette.middleware.cors import CORSMiddleware
from starlette.responses import FileResponse
from starlette.staticfiles import StaticFiles
app = 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)