Python使用fastAPI如何實(shí)現(xiàn)一個(gè)流式傳輸接口
1. 使用fastapi實(shí)現(xiàn)流式傳輸
1.1 服務(wù)端 fastapi_server.py
編寫服務(wù)端代碼fastapi_server.py。
服務(wù)端代碼主要使用了fastapi和uvicorn兩個(gè)庫。
#!/usr/bin/env python # coding=utf-8 # @Time : 2024/1/31 19:13 # @Software: PyCharm from fastapi import FastAPI from fastapi.responses import StreamingResponse import time import uvicorn app = FastAPI() async def generate_data(): for i in range(1, 11): time.sleep(1) # 模擬每秒生成一個(gè)塊的耗時(shí)操作 yield f"FASTAPI Chunk {i}\n" @app.get("/stream") async def stream_data(): return StreamingResponse(generate_data(), media_type="text/plain") if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=8001)
1.2客戶端 (requests)
使用python編寫一個(gè)客戶端stream_client.py,進(jìn)行流式接收。
#!/usr/bin/env python # coding=utf-8 # @Time : 2024/1/31 19:14 # # stream_client.py import requests url = "http://127.0.0.1:8001/stream/" # 替換為你的實(shí)際接口地址 def test1(): try: response = requests.get(url, stream=True) # stream參數(shù)為True if response.status_code == 200: for chunk in response.iter_content(chunk_size=7): # 這行很重要哦 if chunk: print(chunk.decode("utf-8"), end="") except requests.RequestException as e: print(f"Request failed: {e}") def test2(): try: response = requests.get(url, stream=True) if response.status_code == 200: for line in response.iter_lines(decode_unicode=True, chunk_size=8): if line: print("Received SSE event:", line) except requests.RequestException as e: print(f"Request failed: {e}") # test1() test2()
1.3 在html中流式顯示
新建一個(gè)client.html文件,放在fastapi_server.py目錄下。
同時(shí)修改fastapi_server.py, 增加一個(gè)BlockIterator迭代器對(duì)長文本進(jìn)行切塊。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Streaming Client (client.html)</title> </head> <body> aaa <div id="output"></div> <script> const outputDiv = document.getElementById('output'); // 替換為你的實(shí)際接口地址 const url = '$FASTAPI$'; // 使用 Fetch API 發(fā)送請(qǐng)求 fetch(url) .then(response => { const reader = response.body.getReader(); return new ReadableStream({ async start(controller) { while (true) { const { done, value } = await reader.read(); // 如果讀取完畢,中止流 if (done) { controller.close(); break; } // 將每個(gè)塊的內(nèi)容添加到頁面上 outputDiv.innerHTML += new TextDecoder().decode(value) +"<br>"; } } }); }) .then(stream => { // 使用 TextStream,將流連接到頁面上的輸出 const textStream = new TextStream(stream); return textStream.pipeTo(new WritableStream({ write: chunk => { // 在這里你可以處理每個(gè)塊的數(shù)據(jù) console.log('Received chunk:', chunk); } })); }) .catch(error => console.error('Error:', error)); </script> </body> </html>
服務(wù)端增加一個(gè)/web_client接口,讀取上述網(wǎng)頁內(nèi)容
#!/usr/bin/env python # coding=utf-8 # @Time : 2024/1/31 19:13 # @Software: PyCharm from fastapi import FastAPI from starlette.responses import HTMLResponse from fastapi.responses import StreamingResponse import time import uvicorn app = FastAPI() CONTENT = """《易經(jīng)》被譽(yù)為諸經(jīng)之首,大道之源,是中華優(yōu)秀傳統(tǒng)文化的總綱領(lǐng),是中華民族五千年智慧的結(jié)晶。他含蓋萬有、綱紀(jì)群倫,是中華文化的杰出代表;他博大精微、包羅萬象,亦是中華文明的源頭。其內(nèi)容涉及哲學(xué)、生命、自然、科學(xué)、政治、天文、地理、文學(xué)、藝術(shù)等諸多領(lǐng)域,是各家共同的經(jīng)典。 《易經(jīng)》包括《連山》《歸藏》《周易》三部易書,現(xiàn)存于世的只有《周易》?!吨芤住废鄠魇侵芪耐醣磺袅h里時(shí),研究《易經(jīng)》所作的結(jié)論。""" class BlockIterator: def __init__(self, text, block_size=10): self.text = text self.block_size = block_size self.index = 0 def __iter__(self): return self def __next__(self): if self.index >= len(self.text): raise StopIteration block = self.text[self.index:self.index + self.block_size] self.index += self.block_size return block async def generate_data(): for i in BlockIterator(CONTENT, block_size=1): time.sleep(0.05) # 模擬每秒生成一個(gè)塊的耗時(shí)操作 # yield f"FASTAPI Chunk {i}\n" yield i @app.get("/web_client", response_class=HTMLResponse) async def read_root(): with open("static/client.html", "r") as file: html_content = file.read() html_content = html_content.replace("$FASTAPI$", "http://127.0.0.1:8001/stream/") return HTMLResponse(content=html_content) @app.get("/stream") async def stream_data(): return StreamingResponse(generate_data(), media_type="text/plain") if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=8001)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
python3中利用filter函數(shù)輸出小于某個(gè)數(shù)的所有回文數(shù)實(shí)例
今天小編就為大家分享一篇 python3中利用filter函數(shù)輸出小于某個(gè)數(shù)的所有回文數(shù)實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11python 使用poster模塊進(jìn)行http方式的文件傳輸?shù)椒?wù)器的方法
今天小編就為大家分享一篇python 使用poster模塊進(jìn)行http方式的文件傳輸?shù)椒?wù)器的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01Python生成器generator和yield關(guān)鍵字的使用
生成器是一種特殊的迭代器,可以通過列表推導(dǎo)式的修改或者使用yield關(guān)鍵字來創(chuàng)建,生成器函數(shù)能夠在迭代時(shí)動(dòng)態(tài)產(chǎn)生值,而不是一次性生成所有值,這有助于節(jié)省內(nèi)存,yield關(guān)鍵字使函數(shù)執(zhí)行暫停并保存當(dāng)前狀態(tài),下次調(diào)用時(shí)從停止處繼續(xù)執(zhí)行2024-09-09pygame游戲之旅 計(jì)算游戲中躲過的障礙數(shù)量
這篇文章主要為大家詳細(xì)介紹了pygame游戲之旅的第8篇,教大家實(shí)現(xiàn)游戲中躲過障礙數(shù)量的計(jì)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11python中pandas庫中DataFrame對(duì)行和列的操作使用方法示例
這篇文章主要介紹了python中pandas庫中DataFrame對(duì)行和列的操作使用方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06使用Python 正則匹配兩個(gè)特定字符之間的字符方法
今天小編就為大家分享一篇使用Python 正則匹配兩個(gè)特定字符之間的字符方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12解決List.append()?在?Python?中不起作用的問題
在?Python?中,我們通常使用?List.append()?方法向列表末尾添加元素,然而,在某些情況下,你可能會(huì)遇到?List.append()?方法不起作用的問題,本文將詳細(xì)討論這個(gè)問題并提供解決方法,需要的朋友可以參考下2023-06-06Flask項(xiàng)目中實(shí)現(xiàn)短信驗(yàn)證碼和郵箱驗(yàn)證碼功能
這篇文章主要介紹了Flask項(xiàng)目中實(shí)現(xiàn)短信驗(yàn)證碼和郵箱驗(yàn)證碼功能,需本文通過截圖實(shí)例代碼的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2019-12-12