microdot.multipart --- การแยกวิเคราะห์ multipart/form-data

แยกวิเคราะห์เนื้อหาคำขอ Content-Type: multipart/form-data -- การเข้ารหัสที่เบราว์เซอร์ใช้สำหรับฟอร์มที่มีฟิลด์ <input type="file"> มี API สองรูปแบบ:

  • FormDataIter แบบสตรีมมิงที่ yield ฟิลด์ทีละตัว -- มีประโยชน์เมื่อแอปพลิเคชันต้องจัดการการอัปโหลดขนาดใหญ่ทีละส่วนบนอุปกรณ์ที่มีหน่วยความจำจำกัด

  • ตัวตกแต่ง with_form_data() ที่บัฟเฟอร์ทุกอย่างและเติมข้อมูล request.form / request.files -- API ที่สะดวกสำหรับการอัปโหลดขนาดปกติ

class FormDataIter

class microdot.multipart.FormDataIter(request)

Async iterator เหนือส่วนต่างๆ ของเนื้อหา multipart ของ request ค่าที่ yield มาเป็นทูเพิล (name, value) โดย value เป็น str สำหรับฟิลด์ปกติและเป็น FileUpload สำหรับฟิลด์ไฟล์

ใช้โดยตรงเมื่อหน่วยความจำสำคัญกว่าความสะดวก:

from microdot.multipart import FormDataIter, FileUpload

@app.post('/upload')
async def upload(request):
    async for name, value in FormDataIter(request):
        if isinstance(value, FileUpload):
            await value.save('/sdcard/' + value.filename)
        else:
            print(name, '=', value)
    return 'ok'

Note

เมื่อวนซ้ำเหนือฟิลด์ไฟล์ ต้องใช้งานไฟล์นั้น (ผ่าน FileUpload.read() หรือ FileUpload.save()) ก่อนการวนซ้ำ async for ถัดไป -- สตรีมพื้นฐานจะถูกทำให้ใช้ไม่ได้เมื่อการวนซ้ำดำเนินต่อ

buffer_size: int

แอตทริบิวต์คลาส ขนาด chunk ที่ใช้ขณะอ่านจากสตรีมคำขอ ค่าเริ่มต้น 256 ไบต์ เพิ่มขึ้นเพื่อปริมาณงานที่ผ่านได้สูงขึ้นแลกกับ RAM

class FileUpload

class microdot.multipart.FileUpload(filename: str, content_type: str | None, read)

ไฟล์ที่อัปโหลดเพียงไฟล์เดียว อินสแตนซ์จะถูก yield โดย FormDataIter และรวบรวมใน request.files โดย with_form_data() โดยปกติแอปพลิเคชันไม่ต้องสร้าง FileUpload โดยตรง

filename: str

ชื่อเดิมของไฟล์ตามที่ไคลเอนต์ส่งมา (ไม่น่าเชื่อถือ -- ห้ามส่งให้ open() โดยไม่ผ่านการตรวจสอบ)

content_type: str | None

MIME type จากส่วนหัว Content-Type ของส่วนนั้น หรือ None หากไม่ระบุ

max_memory_size: int

แอตทริบิวต์คลาส ค่าขีดแบ่ง (เป็นไบต์) ที่ copy() จะเปลี่ยนจากการบัฟเฟอร์ในหน่วยความจำไปเป็นไฟล์ชั่วคราว ค่าเริ่มต้น 1024

async read(n: int = -1)

อ่านไม่เกิน n ไบต์จากสตรีมการอัปโหลด -1 อ่านจนสิ้นสุด

async save(path_or_file)

บันทึกการอัปโหลดลงใน path_or_file ซึ่งอาจเป็นพาธของระบบไฟล์หรือออบเจ็กต์ไฟล์ที่เปิดอยู่แล้ว

async copy(max_memory_size: int | None = None)

บัฟเฟอร์การอัปโหลด (ในหน่วยความจำ RAM หรือในไฟล์ชั่วคราว ขึ้นอยู่กับ max_memory_size) เพื่อให้สามารถแยกวิเคราะห์เนื้อหา multipart ที่เหลือได้โดยไม่ทำให้สตรีมเดิมใช้ไม่ได้ ตัวตกแต่ง with_form_data() จะเรียกฟังก์ชันนี้โดยอัตโนมัติ

async close()

ปล่อยไฟล์ชั่วคราวที่สร้างโดย copy() ออก จะถูกเรียกโดยอัตโนมัติเมื่อคำขอเสร็จสิ้นหากการอัปโหลดไปถึง request.files ผ่าน with_form_data()

ตัวตกแต่งระดับโมดูล

microdot.multipart.with_form_data(f)

ตัวตกแต่งที่แยกวิเคราะห์เนื้อหา multipart ล่วงหน้าและเติมข้อมูล request.form และ request.files ก่อนที่ตัวจัดการจะทำงาน:

from microdot import Microdot
from microdot.multipart import with_form_data

app = Microdot()

@app.post('/upload')
@with_form_data
async def upload(request):
    print('fields:', dict(request.form))
    for name, file in request.files.items():
        await file.save('/sdcard/' + sanitize(file.filename))
    return 'ok'

การอัปโหลดไฟล์จะถูกบัฟเฟอร์ผ่าน FileUpload.copy() ดังนั้นตัวจัดการสามารถวนซ้ำ request.files และ request.form ได้อย่างอิสระ ไฟล์ชั่วคราวจะถูกล้างข้อมูลโดยอัตโนมัติเมื่อคำขอสิ้นสุด

สำหรับการอัปโหลดที่ใหญ่กว่าสองสามเมกะไบต์ ควรใช้ API สตรีมมิง FormDataIter แทน with_form_data() จะสะสมคำขอทั้งหมดในหน่วยความจำหรือในระบบไฟล์ก่อนที่ตัวจัดการจะทำงาน