好記性不如爛筆頭
內(nèi)容來(lái)自 [ 面試寶典-中級(jí)難度Fast API面試題合集](https://offer.houxu6.top/tag/Fast API)
問(wèn): FastAPI是一個(gè)基于HTTP協(xié)議的Python Web框架愉老,請(qǐng)問(wèn)FastAPI有哪些特點(diǎn)和優(yōu)勢(shì)?
FastAPI是一個(gè)現(xiàn)代剖效、高性能的Python Web框架嫉入,用于構(gòu)建RESTful API和Web服務(wù)。以下是FastAPI的一些主要特點(diǎn)和優(yōu)勢(shì):
-
易學(xué)易用:
- FastAPI的設(shè)計(jì)易于學(xué)習(xí)和使用璧尸,特別是對(duì)于熟悉Python的人而言咒林。
- 語(yǔ)法簡(jiǎn)潔明了,且具有高度可讀性爷光。
-
高性能:
- FastAPI聲稱性能可以與Node.js和Go相媲美垫竞,是最快的Python框架之一。
- 這得益于其基于Starlette和Pydantic庫(kù)的實(shí)現(xiàn)。
-
快速編碼:
- 開(kāi)發(fā)速度比傳統(tǒng)方法提高約200%到300%欢瞪,這有助于縮短項(xiàng)目開(kāi)發(fā)周期活烙。
-
類型安全:
- 利用Python的類型提示來(lái)提供更強(qiáng)的代碼檢查和錯(cuò)誤預(yù)防能力。
- 自動(dòng)文檔生成:利用類型信息自動(dòng)生成交互式的API文檔(Swagger UI或ReDoc)遣鼓。
-
安全性:
- 支持OpenAPI v3規(guī)范啸盏,并通過(guò)JSON Schema驗(yàn)證請(qǐng)求和響應(yīng)數(shù)據(jù)。
- 內(nèi)置支持多種認(rèn)證和授權(quán)方式骑祟,如OAuth2等回懦。
-
異步處理:
- 基于異步IO(asyncio),使得FastAPI能夠高效地處理高并發(fā)場(chǎng)景次企。
-
輕量級(jí):
- 雖然功能強(qiáng)大怯晕,但FastAPI仍然是一個(gè)輕量級(jí)的框架,依賴較少缸棵。
-
兼容性:
- 兼容各大主流Web服務(wù)器舟茶,包括Uvicorn、Gunicorn等蛉谜。
-
社區(qū)支持:
- FastAPI有一個(gè)活躍的開(kāi)發(fā)者社區(qū)稚晚,因此有豐富的第三方庫(kù)和支持資源。
-
可擴(kuò)展性:
- 可以輕松地與其他庫(kù)和框架集成型诚,以滿足特定項(xiàng)目需求客燕。
這些特性使得FastAPI成為許多企業(yè)和開(kāi)發(fā)者在構(gòu)建高性能API時(shí)的理想選擇。
問(wèn): FastAPI如何處理請(qǐng)求和響應(yīng)的HTTP頭部信息狰贯?
在FastAPI中也搓,可以使用HTTPException
和自定義響應(yīng)類來(lái)處理請(qǐng)求和響應(yīng)的HTTP頭部信息。以下是一些方法:
-
通過(guò)
HTTPException
設(shè)置狀態(tài)碼和頭部:- 當(dāng)需要返回錯(cuò)誤或異常響應(yīng)時(shí)涵紊,可以使用
HTTPException
類傍妒。 - 你可以指定一個(gè)可選的
headers
參數(shù)來(lái)添加HTTP頭部。
- 當(dāng)需要返回錯(cuò)誤或異常響應(yīng)時(shí)涵紊,可以使用
from fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/")
async def main():
headers = {"X-Custom-Header": "Value"}
raise HTTPException(status_code=403, detail="Access denied", headers=headers)
-
使用
Response
或自定義響應(yīng)類設(shè)置頭部:- 在某些情況下摸柄,你可能希望控制整個(gè)響應(yīng)對(duì)象颤练,包括其狀態(tài)碼、內(nèi)容和頭部驱负。
- 使用
fastapi.responses.Response
類或創(chuàng)建自己的自定義響應(yīng)類嗦玖。
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse
app = FastAPI()
@app.get("/")
async def main():
headers = {"X-Custom-Header": "Value"}
content = {"message": "Hello, world!"}
return Response(content=json.dumps(content), media_type="application/json", headers=headers)
# 或者使用JSONResponse
from pydantic import BaseModel
class CustomResponse(BaseModel):
message: str
@app.get("/")
async def main():
headers = {"X-Custom-Header": "Value"}
response = CustomResponse(message="Hello, world!")
return JSONResponse(content=response.dict(), status_code=200, headers=headers)
以上代碼展示了如何在FastAPI中處理請(qǐng)求和響應(yīng)的HTTP頭部信息。根據(jù)你的需求跃脊,可以選擇最適合的方法來(lái)實(shí)現(xiàn)所需的頭部功能宇挫。
問(wèn): FastAPI如何處理POST請(qǐng)求的JSON數(shù)據(jù)?
在FastAPI中酪术,處理POST請(qǐng)求的JSON數(shù)據(jù)非常簡(jiǎn)單器瘪。只需使用Body
類和Pydantic模型來(lái)定義預(yù)期的數(shù)據(jù)結(jié)構(gòu)即可。以下是一個(gè)簡(jiǎn)單的例子:
-
首先,創(chuàng)建一個(gè)Pydantic模型:
- 這個(gè)模型將定義你期望從客戶端接收的數(shù)據(jù)結(jié)構(gòu)橡疼。
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
-
然后援所,在路由函數(shù)中使用
Body
類:- 在路由裝飾器中,將參數(shù)類型設(shè)置為
Body
類衰齐,并傳遞你的Pydantic模型作為參數(shù)任斋。
- 在路由裝飾器中,將參數(shù)類型設(shè)置為
from fastapi import FastAPI, Body
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item = Body(...)):
return item
在這個(gè)例子中继阻,F(xiàn)astAPI會(huì)自動(dòng)解析并驗(yàn)證接收到的JSON數(shù)據(jù)耻涛,將其轉(zhuǎn)換為 Item
對(duì)象,并傳遞給路由函數(shù)瘟檩。如果請(qǐng)求中的JSON數(shù)據(jù)不符合 Item
模型的要求(例如缺少必要的字段或包含無(wú)效的值)抹缕,F(xiàn)astAPI將返回一個(gè)錯(cuò)誤響應(yīng)。
注意:這里的 Body(...)
是一個(gè)特殊語(yǔ)法墨辛,表示此參數(shù)是必需的卓研。如果你想讓某個(gè)參數(shù)可選,可以使用 Body(None)
或 Body(x=None)
睹簇,其中 x
是默認(rèn)值奏赘。
此外,F(xiàn)astAPI還支持其他方法來(lái)處理請(qǐng)求體太惠,包括表單數(shù)據(jù)磨淌、多部分文件等。你可以查閱FastAPI官方文檔以獲取更多信息凿渊。
問(wèn): FastAPI如何處理GET請(qǐng)求的查詢參數(shù)梁只?
在FastAPI中,處理GET請(qǐng)求的查詢參數(shù)非常簡(jiǎn)單埃脏。首先搪锣,你需要定義一個(gè)函數(shù)來(lái)處理這些參數(shù)。然后彩掐,在這個(gè)函數(shù)上使用@app.get裝飾器构舟,并將需要的查詢參數(shù)添加到路徑操作裝飾器中。
以下是一個(gè)示例:
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/")
async def read_items(q: str):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results["q"] = q
return results
在這個(gè)例子中堵幽,我們有一個(gè)名為read_items
的函數(shù)狗超,它接受一個(gè)名為q
的查詢參數(shù)。當(dāng)用戶訪問(wèn)/items/
路徑并提供查詢參數(shù)(例如:/items?q=foo
)時(shí)谐檀,F(xiàn)astAPI會(huì)自動(dòng)將該查詢參數(shù)解析為字符串抡谐,并將其作為參數(shù)傳遞給read_items
函數(shù)。
如果你需要接收多個(gè)查詢參數(shù)桐猬,你可以像下面這樣定義你的函數(shù):
@app.get("/items/")
async def read_items(q: str, skip: int = 0, limit: int = 10):
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
if q:
results["q"] = q
return results[skip:limit]
在這個(gè)例子中麦撵,我們?cè)黾恿藘蓚€(gè)額外的查詢參數(shù):skip
和limit
。這兩個(gè)參數(shù)都是可選的,并且都有默認(rèn)值免胃。如果用戶提供了這些參數(shù)(例如:/items?q=foo&skip=10&limit=5
)音五,F(xiàn)astAPI會(huì)將它們解析為整數(shù),并將它們作為參數(shù)傳遞給read_items
函數(shù)羔沙。
問(wèn): FastAPI如何處理文件上傳請(qǐng)求躺涝?
在FastAPI中,處理文件上傳請(qǐng)求非常簡(jiǎn)單扼雏。首先坚嗜,你需要定義一個(gè)函數(shù)來(lái)處理這些上傳的文件。然后诗充,在這個(gè)函數(shù)上使用@app.post裝飾器苍蔬,并將需要的文件參數(shù)添加到路徑操作裝飾器中。
以下是一個(gè)示例:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/uploadfile/")
async def create_upload_file(file: bytes = File(...)):
return {"file_size": len(file)}
在這個(gè)例子中蝴蜓,我們有一個(gè)名為create_upload_file
的函數(shù)碟绑,它接受一個(gè)名為file
的文件參數(shù)。當(dāng)用戶訪問(wèn)/uploadfile/
路徑并上傳文件時(shí)茎匠,F(xiàn)astAPI會(huì)自動(dòng)將該文件解析為字節(jié)流格仲,并將其作為參數(shù)傳遞給create_upload_file
函數(shù)。
如果你想要接收多個(gè)文件诵冒,你可以像下面這樣定義你的函數(shù):
from typing import List
from fastapi import File, UploadFile
@app.post("/uploadfiles/")
async def create_upload_files(files: List[bytes] = File(...)):
return {"file_sizes": [len(file) for file in files]}
在這個(gè)例子中凯肋,我們?cè)黾恿硕鄠€(gè)文件參數(shù):files
。如果用戶提供了這些參數(shù)(例如:同時(shí)上傳多個(gè)文件)造烁,F(xiàn)astAPI會(huì)將它們解析為字節(jié)流列表否过,并將它們作為參數(shù)傳遞給create_upload_files
函數(shù)。
另外惭蟋,如果你想獲取上傳文件的原始名稱和MIME類型等信息苗桂,可以使用UploadFile
對(duì)象代替bytes
類型。以下是使用UploadFile
的例子:
from fastapi import FastAPI, File, UploadFile
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
content = await file.read()
return {"filename": file.filename, "content_type": file.content_type, "file_size": len(content)}
在這個(gè)例子中告组,我們可以從UploadFile
對(duì)象中獲取上傳文件的原始名稱煤伟、MIME類型以及內(nèi)容。
問(wèn): FastAPI如何處理WebSocket連接木缝?
在FastAPI中诅炉,處理WebSocket連接可以使用Starlette的WebSocket功能呵曹。首先,你需要定義一個(gè)函數(shù)來(lái)處理WebSocket連接和數(shù)據(jù)傳輸。然后憨攒,在這個(gè)函數(shù)上使用@app.websocket裝飾器吝沫,并將需要的路徑添加到裝飾器中烹棉。
以下是一個(gè)示例:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from starlette.websockets import WebSocket
app = FastAPI()
html = """
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Echo</title>
</head>
<body>
<h1>WebSocket Echo</h1>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<script>
var ws = new WebSocket("ws://localhost:8000/ws/echo");
ws.onmessage = function(event) {
var messages = document.getElementById('messages')
var message = document.createElement('li')
var content = document.createTextNode(event.data)
message.appendChild(content)
messages.appendChild(message);
};
function sendMessage(event) {
var input = document.getElementById("messageText")
ws.send(input.value);
event.preventDefault()
}
</script>
</body>
</html>
"""
@app.get("/")
async def get():
return HTMLResponse(html)
@app.websocket("/ws/echo/")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
while True:
data = await websocket.receive_text()
await websocket.send_text(f"You said: {data}")
在這個(gè)例子中,我們有一個(gè)名為websocket_endpoint
的函數(shù)掸冤,它接受一個(gè)名為websocket
的WebSocket對(duì)象。當(dāng)用戶通過(guò)WebSocket連接訪問(wèn)/ws/echo/
路徑時(shí)友雳,F(xiàn)astAPI會(huì)自動(dòng)創(chuàng)建一個(gè)新的WebSocket連接稿湿,并將其作為參數(shù)傳遞給websocket_endpoint
函數(shù)。
在websocket_endpoint
函數(shù)內(nèi)部押赊,我們首先調(diào)用await websocket.accept()
來(lái)接受新的WebSocket連接饺藤。然后,我們進(jìn)入一個(gè)無(wú)限循環(huán)流礁,等待接收客戶端發(fā)送的數(shù)據(jù)(通過(guò)await websocket.receive_text()
)涕俗。每當(dāng)收到新數(shù)據(jù)時(shí),我們就將數(shù)據(jù)回顯給客戶端(通過(guò)await websocket.send_text()
)崇棠。
請(qǐng)注意咽袜,為了使這個(gè)示例工作,你需要提供一個(gè)HTML頁(yè)面枕稀,其中包含一個(gè)與WebSocket服務(wù)器建立連接的JavaScript代碼。你可以參考上面示例中的HTML代碼來(lái)實(shí)現(xiàn)這一點(diǎn)谜嫉。
問(wèn): FastAPI如何處理Cookie萎坷?
在FastAPI中,處理Cookie非常簡(jiǎn)單沐兰。你可以使用fastapi.responses.Response
對(duì)象的set_cookie
方法來(lái)設(shè)置Cookie哆档,或者使用fastapi.requests.Request
對(duì)象的cookies
屬性來(lái)獲取Cookie。
以下是一個(gè)示例:
from fastapi import FastAPI, Request, Response
app = FastAPI()
@app.get("/set-cookie/")
async def set_cookie(response: Response):
response.set_cookie(key="cookie_name", value="cookie_value")
return {"message": "Cookie has been set"}
@app.get("/get-cookie/")
async def get_cookie(request: Request):
cookie_value = request.cookies.get("cookie_name")
if cookie_value:
return {"message": f"Cookie value is {cookie_value}"}
else:
return {"message": "Cookie not found"}
在這個(gè)例子中住闯,我們有兩個(gè)路由:一個(gè)用于設(shè)置Cookie(/set-cookie/
)瓜浸,另一個(gè)用于獲取Cookie(/get-cookie/
)。
在set_cookie
函數(shù)中比原,我們首先創(chuàng)建了一個(gè)Response
對(duì)象插佛,并調(diào)用了它的set_cookie
方法來(lái)設(shè)置Cookie。這個(gè)方法接受兩個(gè)參數(shù):一個(gè)是Cookie的名稱量窘,另一個(gè)是Cookie的值雇寇。然后,我們返回一個(gè)包含消息的字典蚌铜。
在get_cookie
函數(shù)中锨侯,我們首先從Request
對(duì)象中獲取了所有可用的Cookie,然后通過(guò)鍵(即Cookie的名稱)查找特定的Cookie冬殃。如果找到了該Cookie囚痴,我們就返回一個(gè)包含消息和Cookie值的字典;否則审葬,我們返回一個(gè)表示找不到Cookie的消息深滚。
請(qǐng)注意骂束,你還可以為set_cookie
方法提供其他選項(xiàng),如過(guò)期時(shí)間成箫、路徑展箱、域等。例如:
response.set_cookie(
key="cookie_name",
value="cookie_value",
max_age=3600,
path="/",
domain="example.com",
)
這將設(shè)置一個(gè)名為“cookie_name”的Cookie蹬昌,其值為“cookie_value”混驰,有效期為一小時(shí),路徑為"/"皂贩,域?yàn)椤癳xample.com”栖榨。
問(wèn): FastAPI如何處理HTTPS請(qǐng)求?
在FastAPI中明刷,處理HTTPS請(qǐng)求需要配置服務(wù)器以支持HTTPS婴栽。以下是在Uvicorn(一個(gè)常用的ASGI服務(wù)器)上啟用HTTPS的示例:
首先,你需要生成或獲取一個(gè)SSL證書和私鑰文件辈末。你可以使用
openssl
命令行工具來(lái)生成它們愚争,或者從權(quán)威證書頒發(fā)機(jī)構(gòu)購(gòu)買。然后挤聘,在你的應(yīng)用程序入口點(diǎn)(如
main.py
)中添加以下代碼轰枝,以指定證書和私鑰文件的位置:
from fastapi import FastAPI
import uvicorn
app = FastAPI()
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=443, ssl_keyfile="path/to/your/key.pem", ssl_certfile="path/to/your/cert.pem")
在這個(gè)例子中,我們調(diào)用了uvicorn.run
函數(shù)组去,并傳入了四個(gè)參數(shù):應(yīng)用程序?qū)ο蟀霸伞⒅鳈C(jī)地址、端口號(hào)以及SSL密鑰文件和證書文件的路徑从隆。
- 最后诚撵,運(yùn)行你的應(yīng)用程序。你應(yīng)該能夠通過(guò)HTTPS訪問(wèn)它键闺,例如:https://localhost:443/
請(qǐng)注意寿烟,如果你正在生產(chǎn)環(huán)境中部署你的應(yīng)用程序,你可能還需要考慮其他安全措施艾杏,如HTTP嚴(yán)格傳輸安全(HSTS)韧衣、TLS版本控制等。
問(wèn): FastAPI如何處理Session管理购桑?
在FastAPI中畅铭,處理Session管理可以使用第三方庫(kù)fastapi-sessions
。以下是一個(gè)示例:
- 首先勃蜘,安裝
fastapi-sessions
庫(kù):
pip install fastapi-sessions
- 然后硕噩,在你的應(yīng)用程序入口點(diǎn)(如
main.py
)中添加以下代碼,以設(shè)置Session的存儲(chǔ)和加密方式:
from fastapi import FastAPI, Request
from fastapi_sessions import SessionManager, CookieBackend, EncryptedCookieSerializer
app = FastAPI()
session_manager = SessionManager(
backend=CookieBackend(serializer=EncryptedCookieSerializer(secret_key="your_secret_key")),
cookie_name="session_id",
)
async def get_session(request: Request):
return await session_manager.get_session(request=request)
@app.on_event("startup")
async def startup():
await session_manager.startup()
@app.on_event("shutdown")
async def shutdown():
await session_manager.shutdown()
在這個(gè)例子中缭贡,我們創(chuàng)建了一個(gè)SessionManager
對(duì)象炉擅,并指定了一個(gè)基于Cookie的后端以及一個(gè)用于加密Cookie的序列化器辉懒。我們還定義了一個(gè)異步函數(shù)get_session
,它從請(qǐng)求對(duì)象中獲取當(dāng)前的Session谍失。
- 最后眶俩,你可以在路由處理器中使用
get_session
函數(shù)來(lái)操作Session。例如:
@app.post("/login/")
async def login(username: str, password: str, request: Request):
user = authenticate_user(username, password)
if user is None:
return {"message": "Invalid username or password"}
session = await get_session(request)
session["user_id"] = user.id
await session_manager.commit(session=session)
return {"message": "Login successful"}
在這個(gè)例子中快鱼,我們?cè)谟脩舻卿洉r(shí)將用戶的ID保存到Session中颠印,并在后續(xù)請(qǐng)求中通過(guò)Session來(lái)識(shí)別已登錄的用戶。
問(wèn): FastAPI如何處理異步請(qǐng)求抹竹?
在FastAPI中线罕,處理異步請(qǐng)求非常簡(jiǎn)單。只需將你的函數(shù)定義為異步函數(shù)(使用async def
)窃判,并使用關(guān)鍵字await
來(lái)調(diào)用其他異步函數(shù)或操作即可钞楼。
以下是一個(gè)示例:
from fastapi import FastAPI, HTTPException
import requests
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
response = await fetch_item_data(item_id)
if not response:
raise HTTPException(status_code=404, detail="Item not found")
return {"item": response}
async def fetch_item_data(item_id: int):
url = f"https://example.com/items/{item_id}"
response = requests.get(url) # 這里實(shí)際上是同步的,但你可以換成一個(gè)異步庫(kù)(如httpx)
if response.status_code == 200:
return response.json()
else:
return None
在這個(gè)例子中袄琳,我們有一個(gè)名為read_item
的路由處理器询件,它接受一個(gè)參數(shù)item_id
。然后跨蟹,我們調(diào)用了fetch_item_data
異步函數(shù)來(lái)獲取該物品的數(shù)據(jù)雳殊。如果找不到該物品,我們就拋出一個(gè)HTTP異常窗轩;否則,我們返回包含物品數(shù)據(jù)的響應(yīng)座咆。
請(qǐng)注意痢艺,雖然這個(gè)例子中的fetch_item_data
函數(shù)實(shí)際上執(zhí)行了一個(gè)同步操作(通過(guò)requests庫(kù)發(fā)送HTTP請(qǐng)求),但在實(shí)際應(yīng)用中介陶,你通常會(huì)使用異步庫(kù)(如httpx)來(lái)執(zhí)行這些操作堤舒。這樣可以提高應(yīng)用程序的性能和可擴(kuò)展性。