स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध
StreamingResponse से बड़ी फ़ाइलें उपलब्ध कराइए और फिर से शुरू किए जा सकने वाले डाउनलोड के लिए HTTP रेंज अनुरोध समर्थित कीजिए।
स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध, CoddyKit पर FastAPI बैकएंड डेवलपमेंट बूटकैंप का एक निःशुल्क पाठ है। यह 4 में से 2वाँ पाठ है। इस अध्ययन पथ के 3 तक कोई भी पाठ पूरा पढ़ना निःशुल्क है — इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ व्यावहारिक अभ्यास भी उपलब्ध कराता है। यह FastAPI बैकएंड डेवलपमेंट बूटकैंप सीखने के मार्ग का हिस्सा है और आपकी प्रगति वेब तथा CoddyKit ऐप पर सिंक होती रहती है। FastAPI बैकएंड डेवलपमेंट बूटकैंप पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
स्ट्रीम प्रतिक्रियाएँ क्यों
डिफ़ॉल्ट रूप से, FastAPI से फ़ाइल लौटाने का अर्थ है भेजने से पहले पूरे पेलोड को मेमोरी में लोड करना। 2 GB के वीडियो के लिए यह विनाशकारी है: मेमोरी अचानक बढ़ती है, पहला बाइट देर से मिलता है और एक साथ कई अनुरोध आने पर सेवा बंद हो सकती है।
स्ट्रीमिंग बॉडी को उपलब्ध होते ही छोटे-छोटे टुकड़ों में भेजकर इस समस्या का समाधान करती है। सर्वर एक समय में केवल एक टुकड़ा रखता है और क्लाइंट को लगभग तुरंत डेटा मिलना शुरू हो जाता है।
StreamingResponse— बाइट्स देने वाले जनरेटर/इटरेटर को लपेटता है।FileResponse— डिस्क से फ़ाइल कुशलतापूर्वक भेजने की सुविधा देता है।- रेंज अनुरोध — क्लाइंट को फ़ाइल का केवल एक भाग प्राप्त करने देते हैं (आगे-पीछे जाना, फिर से शुरू करना)।
इस पाठ में इन तीनों को बनाया जाएगा और अंत में फिर से शुरू किए जा सकने वाले डाउनलोड तैयार किए जाएँगे।
बाइट्स देने वाला जनरेटर
स्ट्रीमिंग की शुरुआत बाइट्स के इटरेबल से होती है। सबसे साफ़ स्रोत Python जनरेटर है, जो पूरी फ़ाइल एक साथ पढ़ने के बजाय निश्चित आकार के टुकड़ों में पढ़ता है।
यहाँ मुख्य विचार को किसी फ़्रेमवर्क से अलग करके दिखाया गया है। जनरेटर हर बार 1 MB देता है, इसलिए फ़ाइल कितनी भी बड़ी हो, अधिकतम मेमोरी खपत बहुत कम रहती है।
def file_chunks(path, chunk_size=1024 * 1024):
with open(path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
yield chunk
if __name__ == "__main__":
import os
with open("sample.bin", "wb") as f:
f.write(b"x" * (3 * 1024 * 1024 + 17))
total = 0
pieces = 0
for chunk in file_chunks("sample.bin"):
total += len(chunk)
pieces += 1
print("bytes:", total)
print("chunks:", pieces)
os.remove("sample.bin")StreamingResponse की मूल बातें
StreamingResponse अपने पहले तर्क के रूप में बाइट्स (या स्ट्रिंग) का कोई भी सिंक या एसिंक्रोनस इटरेबल लेता है। आप media_type सेट करते हैं, ताकि ब्राउज़र को पता हो कि बॉडी को कैसे संभालना है।
ध्यान दें कि हम जनरेटर ऑब्जेक्ट को स्वयं देते हैं, उसका परिणाम नहीं—भेजते समय FastAPI इसे धीरे-धीरे इटरेट करता है।
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
def file_chunks(path, chunk_size=1024 * 1024):
with open(path, "rb") as f:
while chunk := f.read(chunk_size):
yield chunk
@app.get("/download/report")
def download_report():
return StreamingResponse(
file_chunks("report.pdf"),
media_type="application/pdf",
)Content-Disposition सेट करना
ब्राउज़र को फ़ाइल दिखाने के बजाय डाउनलोड करवाने और फ़ाइल नाम चुनने के लिए Content-Disposition हेडर भेजें।
attachment— डाउनलोड संवाद को बाध्य करता है।inline— संभव होने पर ब्राउज़र में दिखाता है।filename="..."— सुझाया गया नाम।
कस्टम हेडर StreamingResponse के headers तर्क के माध्यम से दें।
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
def file_chunks(path, chunk_size=1024 * 1024):
with open(path, "rb") as f:
while chunk := f.read(chunk_size):
yield chunk
@app.get("/export/users.csv")
def export_users():
headers = {
"Content-Disposition": 'attachment; filename="users.csv"'
}
return StreamingResponse(
file_chunks("users.csv"),
media_type="text/csv",
headers=headers,
)बनाए गए डेटा को तुरंत स्ट्रीम करना
स्ट्रीमिंग केवल डिस्क पर मौजूद फ़ाइलों तक सीमित नहीं है। आप बॉडी को क्रमिक रूप से बना सकते हैं—उदाहरण के लिए, डेटाबेस कर्सर से बहुत बड़े CSV को पंक्ति-दर-पंक्ति निर्यात करना, बिना पूरी स्ट्रिंग को मेमोरी में बनाए।
नीचे दिया गया जनरेटर एक बार में एक CSV पंक्ति देता है। प्रत्येक yield तैयार होते ही क्लाइंट को भेज दिया जाता है।
import csv
import io
def csv_stream(rows):
buffer = io.StringIO()
writer = csv.writer(buffer)
writer.writerow(["id", "name", "score"])
yield buffer.getvalue()
for row in rows:
buffer.seek(0)
buffer.truncate(0)
writer.writerow(row)
yield buffer.getvalue()
if __name__ == "__main__":
data = [(i, f"user{i}", i * 10) for i in range(5)]
output = "".join(csv_stream(data))
print(output, end="")FileResponse: आसान तरीका
जब आपको केवल डिस्क से मौजूद फ़ाइल भेजनी हो, तो जनरेटर जोड़ने की तुलना में FileResponse सरल है। Starlette इसे कुशलतापूर्वक स्ट्रीम करता है और आपके लिए उचित हेडर सेट करता है।
- एक्सटेंशन से
Content-Typeका अनुमान लगाता है। Content-Lengthअपने आप सेट करता है।- कैशिंग के लिए ETag और Last-Modified जोड़ता है।
- महत्वपूर्ण रूप से, यह पहले से ही रेंज अनुरोधों का समर्थन करता है।
स्थिर, डिस्क पर मौजूद फ़ाइलों के लिए मैन्युअल StreamingResponse के बजाय FileResponse को प्राथमिकता दें।
from fastapi import FastAPI
from fastapi.responses import FileResponse
app = FastAPI()
@app.get("/media/{name}")
def serve_media(name: str):
return FileResponse(
path=f"media/{name}",
filename=name,
media_type="video/mp4",
)HTTP रेंज अनुरोध क्या है
रेंज अनुरोध से क्लाइंट किसी संसाधन के केवल एक हिस्से के लिए अनुरोध कर सकता है। ब्राउज़र भेजता है:
Range: bytes=1048576-2097151
सर्वर 206 Partial Content स्थिति और ये हेडर लौटाता है:
Content-Range: bytes 1048576-2097151/5242880— भेजे जा रहे हिस्से और कुल आकार को दर्शाता है।Content-Length— केवल इस हिस्से की लंबाई।Accept-Ranges: bytes— बताता है कि रेंज समर्थित हैं।
इसी से वीडियो में मनचाहे स्थान पर जाना संभव होता है (0–4 मिनट डाउनलोड किए बिना सीधे 5वें मिनट पर जाना) और फिर से शुरू किए जा सकने वाले डाउनलोड काम करते हैं (जहाँ कनेक्शन टूट गया था, वहीं से जारी रखना)।
Range हेडर को पार्स करना
रेंज का समर्थन मैन्युअल रूप से करने के लिए आपको Range हेडर को पार्स करना होगा। इसका प्रारूप bytes=start-end होता है, जिसमें किसी भी तरफ का मान छोड़ा जा सकता है:
bytes=500-999— 500 से 999 तक के बाइट।bytes=500-— 500 से अंत तक।bytes=-500— अंतिम 500 बाइट (suffix range)।
यह स्वतंत्र पार्सर दिए गए फ़ाइल आकार के लिए समावेशी (start, end) ऑफ़सेट लौटाता है।
def parse_range(header, file_size):
units, _, rng = header.partition("=")
if units.strip() != "bytes":
raise ValueError("only byte ranges supported")
start_s, _, end_s = rng.strip().partition("-")
if start_s == "":
# suffix range: last N bytes
length = int(end_s)
start = max(file_size - length, 0)
end = file_size - 1
else:
start = int(start_s)
end = int(end_s) if end_s else file_size - 1
end = min(end, file_size - 1)
if start > end:
raise ValueError("unsatisfiable range")
return start, end
if __name__ == "__main__":
size = 5000
print(parse_range("bytes=0-499", size))
print(parse_range("bytes=4500-", size))
print(parse_range("bytes=-100", size))केवल अनुरोधित हिस्से को पढ़ना
जब आपके पास (start, end) हो, तो आपको केवल उसी विंडो को स्ट्रीम करना होगा। ऑफ़सेट पर जाने के लिए file.seek(start) का उपयोग करें, फिर शेष बाइट गिनते हुए हिस्सों में पढ़ें, ताकि end से आगे कभी न पढ़ा जाए।
यह जनरेटर ठीक end - start + 1 बाइट लौटाता है।
def ranged_chunks(path, start, end, chunk_size=1024 * 1024):
remaining = end - start + 1
with open(path, "rb") as f:
f.seek(start)
while remaining > 0:
chunk = f.read(min(chunk_size, remaining))
if not chunk:
break
remaining -= len(chunk)
yield chunk
if __name__ == "__main__":
import os
with open("blob.bin", "wb") as f:
f.write(bytes(range(256)) * 40) # 10240 bytes
got = b"".join(ranged_chunks("blob.bin", 100, 199, chunk_size=32))
print("length:", len(got))
print("first byte:", got[0])
os.remove("blob.bin")पूर्ण रेंज-सक्षम एंडपॉइंट
अब हम सब कुछ एक FastAPI एंडपॉइंट में जोड़ते हैं, जो पूर्ण और आंशिक दोनों डाउनलोड संभालता है:
Rangeहेडर नहीं है → पूरी फ़ाइल को 200 OK के साथ स्ट्रीम करें।- मान्य
Range→ हिस्से को 206 Partial Content औरContent-Rangeके साथ स्ट्रीम करें। - असंतोषजनक रेंज →
Content-Range: bytes */sizeहेडर के साथ 416 लौटाएँ।
हमेशा Accept-Ranges: bytes का संकेत दें, ताकि क्लाइंट को पता रहे कि मनचाही स्थिति पर जाना संभव है।
import os
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse, Response
app = FastAPI()
VIDEO = "media/movie.mp4"
def ranged_chunks(path, start, end, chunk_size=1024 * 1024):
remaining = end - start + 1
with open(path, "rb") as f:
f.seek(start)
while remaining > 0 and (chunk := f.read(min(chunk_size, remaining))):
remaining -= len(chunk)
yield chunk
@app.get("/video")
def stream_video(request: Request):
size = os.path.getsize(VIDEO)
range_header = request.headers.get("range")
if range_header is None:
return StreamingResponse(
ranged_chunks(VIDEO, 0, size - 1),
media_type="video/mp4",
headers={"Accept-Ranges": "bytes",
"Content-Length": str(size)},
)
start, end = parse_range(range_header, size)
headers = {
"Content-Range": f"bytes {start}-{end}/{size}",
"Accept-Ranges": "bytes",
"Content-Length": str(end - start + 1),
}
return StreamingResponse(
ranged_chunks(VIDEO, start, end),
status_code=206,
media_type="video/mp4",
headers=headers,
)असिंक्रोनस स्ट्रीमिंग और सफ़ाई
अधिक लोड में गैर-अवरोधक I/O के लिए async generator का उपयोग करें। डिस्क को थ्रेड पूल के भीतर पढ़ने से इवेंट लूप खाली रहता है; aiofiles जैसी लाइब्रेरी यह काम आपके लिए करती हैं।
दो महत्वपूर्ण नियम:
- स्ट्रीमिंग आपके फ़ंक्शन के लौटने के बाद चलती है, इसलिए जनरेटर के भीतर खोले गए संसाधनों को
finallyब्लॉक में मुक्त करना आवश्यक है। - यदि स्ट्रीम के बीच में क्लाइंट का कनेक्शन टूट जाता है, तो FastAPI जनरेटर के भीतर अपवाद उठाता है — फिर भी वह
finallyचलता है, इसलिए हैंडल कभी लीक नहीं होते।
import aiofiles
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def async_chunks(path, chunk_size=1024 * 1024):
f = await aiofiles.open(path, "rb")
try:
while chunk := await f.read(chunk_size):
yield chunk
finally:
await f.close()
@app.get("/async-download")
async def async_download():
return StreamingResponse(
async_chunks("big.bin"),
media_type="application/octet-stream",
headers={"Accept-Ranges": "bytes"},
)त्वरित जाँच
10000 बाइट की फ़ाइल के लिए क्लाइंट Range: bytes=2000-2999 भेजता है। सही आंशिक डाउनलोड के लिए आपके एंडपॉइंट को कौन-सा स्थिति कोड और कौन-से हेडर लौटाने चाहिए?
पुनरावलोकन
अब आप बड़ी मीडिया फ़ाइलों को कुशलता से उपलब्ध करा सकते हैं और फिर से शुरू किए जा सकने वाले तथा मनचाही स्थिति से डाउनलोड का समर्थन कर सकते हैं।
- StreamingResponse बाइटों के पुनरावर्तनीय अनुक्रम को लपेटता है, इसलिए अधिकतम मेमोरी पूरी फ़ाइल के बजाय केवल एक हिस्से के बराबर होती है।
- FileResponse डिस्क पर मौजूद फ़ाइलों के लिए आसान विकल्प है और पहले से ही रेंज तथा कैशिंग हेडर का समर्थन करता है।
- रेंज अनुरोध
Range: bytes=start-endभेजता है; उत्तर में 206,Content-Range, हिस्से के आकार के बराबरContent-LengthऔरAccept-Ranges: bytesदें। - हेडर को पार्स करें (suffix
bytes=-Nसहित),seek(start)करें और शेष बाइटों पर नज़र रखते हुए पढ़ें, ताकि सीमा से आगे न पढ़ें। - क्लाइंट के बीच में कनेक्शन तोड़ने पर भी हैंडल बंद करने के लिए
finallyब्लॉक वाले async generators का उपयोग करें।
एआई शिक्षक के साथ FastAPI बैकएंड डेवलपमेंट बूटकैंप सीखें — निःशुल्क
अपने ब्राउज़र में वास्तविक कोड लिखें और चलाएँ, चौबीसों घंटे एआई शिक्षक से तुरंत सहायता पाएँ, और वेब या ऐप पर वहीं से शुरू करें जहाँ आपने छोड़ा था।
- पाठ्यक्रम
- 21
- पाठ
- 84
अक्सर पूछे जाने वाले प्रश्न
क्या “स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध” पाठ निःशुल्क है?
हाँ — FastAPI बैकएंड डेवलपमेंट बूटकैंप अध्ययन पथ के 3 तक कोई भी पाठ, जिसमें “स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध” भी शामिल है, यहाँ वेब पर पूरा पढ़ना निःशुल्क है। इसके बाद CoddyKit PRO हर पाठ अनलॉक करता है, साथ ही अंतर्निर्मित कोड संपादक और चौबीसों घंटे एआई शिक्षक के साथ इंटरैक्टिव अभ्यास भी उपलब्ध कराता है। FastAPI बैकएंड डेवलपमेंट बूटकैंप पाठ्यक्रम में कुल 4 पाठ शामिल हैं।
“स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध” में मैं क्या सीखूँगा?
StreamingResponse से बड़ी फ़ाइलें उपलब्ध कराइए और फिर से शुरू किए जा सकने वाले डाउनलोड के लिए HTTP रेंज अनुरोध समर्थित कीजिए। आप ब्राउज़र में सीधे चलाए जाने वाले व्यावहारिक कोड के साथ FastAPI बैकएंड डेवलपमेंट बूटकैंप का अभ्यास करते हैं, और पाठ पूरा करते समय 24/7 एआई ट्यूटर आपके प्रश्नों के उत्तर देता है।
क्या FastAPI बैकएंड डेवलपमेंट बूटकैंप शुरू करने के लिए मुझे किसी अनुभव की आवश्यकता है?
पहले के अनुभव की आवश्यकता नहीं है। CoddyKit पर FastAPI बैकएंड डेवलपमेंट बूटकैंप शुरुआती से लेकर उन्नत शिक्षार्थियों तक सभी के लिए व्यवस्थित किया गया है, इसलिए आप यहीं से या शुरुआत से सीखना शुरू कर सकते हैं और अपनी गति से आगे बढ़ सकते हैं। यह 4 में से 2वाँ पाठ है।
“स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध” पाठ पूरा करने में कितना समय लगता है?
CoddyKit का अधिकांश पाठ लगभग 5–10 मिनट में पूरा हो जाता है। हर पाठ छोटा और संवादात्मक है, इसलिए आप लगातार प्रगति करते हैं और वेब या ऐप पर वहीं से सीखना जारी रख सकते हैं जहाँ आपने छोड़ा था।
क्या मैं इस FastAPI बैकएंड डेवलपमेंट बूटकैंप पाठ में कोड लिख और चला सकता हूँ?
हाँ। हर FastAPI बैकएंड डेवलपमेंट बूटकैंप पाठ में एक अंतर्निर्मित कोड संपादक शामिल है, जिससे आप सीधे अपने ब्राउज़र में वास्तविक कोड लिख और चला सकते हैं और तुरंत एआई प्रतिक्रिया पा सकते हैं—स्थानीय सेटअप की आवश्यकता नहीं है।
इस पाठ्यक्रम के सभी पाठ
- मल्टीपार्ट अपलोड और सामग्री सत्यापन
- स्ट्रीमिंग प्रतिक्रियाएँ और रेंज अनुरोध
- S3-संगत बकेट में स्टोरेज ऑफलोड करना
- अतुल्यकालिक छवि और दस्तावेज़ रूपांतरण