PPDF123
How-to2026-08-27อ่านประมาณ 2 นาที

เมื่ออัปโหลด PDF ขนาดใหญ่แล้วถูกปฏิเสธ: ขีดจำกัด 100 MiB ของบอดีคำขอ และข้อผิดพลาดที่ชี้ผิดทาง

บอดีของคำขอหนึ่งครั้งมีได้ถึง 100 MiB หรือ 104,857,600 ไบต์ รวมกรอบของ multipart ด้วย เมื่อเกินขีดจำกัด เอนด์พอยต์ของโอเปอเรชันจะตอบ 400 พร้อมรหัส bad_request ไม่ใช่ 413 ส่วนเมื่อมี Idempotency-Key จะมีขีดจำกัด 100 MiB อีกชั้นหนึ่งบนบัฟเฟอร์ของการตอบกลับ เกินแล้วได้ 500 และไม่มีอะไรถูกแคช

PDF123 · Updated 2026-08-27

PDF ขนาดใหญ่ที่อัปโหลดไม่ขึ้นมักไม่ใช่ไฟล์ที่เสีย แต่เป็นเพราะบอดีของคำขอชนขีดจำกัดต่อคำขอหนึ่งครั้ง: 100 MiB หรือ 104,857,600 ไบต์ ตัวเลขนี้วัดจากบอดีทั้งก้อน รวมขอบเขตของ multipart และส่วนหัวของฟิลด์ และจำนวนนี้พอดีผ่าน ขณะที่เพิ่มอีก 1 ไบต์ถูกปฏิเสธ

ข้อผิดพลาดที่ตอบกลับมาชี้ไปคนละทาง เอนด์พอยต์ของโอเปอเรชันตอบ 400 โดยตั้ง code เป็น bad_request และรายละเอียดบอกว่าอ่านฟิลด์ multipart ไม่สำเร็จ โดยไม่มีการกล่าวถึงขนาดเลย ไคลเอนต์ที่แยกทางตาม code จะจัดมันเป็นข้อผิดพลาดด้านพารามิเตอร์ แล้วไปตรวจชื่อฟิลด์ ทั้งที่สิ่งที่ต้องแก้คือขนาดไฟล์

100 MiB เดียวกันยังคุมทิศทางตรงข้ามด้วย คำขอที่พา Idempotency-Key มาจะอ่านการตอบกลับเข้าหน่วยความจำก่อนแคช เทียบกับตัวเลขเดียวกัน และเมื่อเกิน ผู้เรียกจะได้รับ 500 ขณะที่โอเปอเรชันทำงานเสร็จไปแล้ว ตัวเลขเดียว กับรูปแบบความล้มเหลวสองแบบที่ตรงข้ามกัน

                     100 MiB = 104,857,600 ไบต์ (จำนวนนี้พอดีผ่าน)
                                   |
                +------------------+------------------+
                |                                     |
         ขาเข้า (บอดีของคำขอ)                 ขาออก (บอดีของการตอบกลับ)
   นับบอดีทั้งก้อน รวมขอบเขต multipart       เฉพาะเมื่อมี Idempotency-Key
   และส่วนหัวของฟิลด์; โอเปอเรชันหนึ่ง         แคชพลาด และต้นทางตอบ 2xx
   กับไปป์ไลน์ใช้ตัวเลขร่วมกัน
   เกิน: 400 + bad_request                   เกิน: 500 และไม่เขียนแคช
   (รายละเอียด: อ่านฟิลด์ multipart ไม่สำเร็จ)

หมายเหตุภาพ: ขีดจำกัดเดียว และสองฝั่งคือขาเข้ากับขาออกของมันให้รหัสสถานะต่างกันพร้อมผลลัพธ์ที่ตรงข้ามกัน

ขีดจำกัดนับบอดีของคำขอทั้งก้อน รวมขอบเขต

100 MiB จำกัดบอดีของคำขอเดียว ไม่ใช่ขนาดของไฟล์เดียว และไม่ใช่ขนาดหลังคลายการบีบอัด

  • โอเปอเรชันเดียวกับไปป์ไลน์หลายขั้นใช้ตัวเลขร่วมกัน การซอยงานเป็น 10 ขั้นในคำขอ /api/v1/pipeline ครั้งเดียวไม่ได้ทำให้เพดานกลายเป็น 1 GB จำนวนขั้นมีผลกับเวลาทำงานเท่านั้น
  • ค่าที่ขอบพอดีผ่าน: บอดีของคำขอ 104,857,600 ไบต์ผ่านไป 104,857,601 ไบต์ไม่ผ่าน
  • บอดีมีส่วนหัวของแต่ละฟิลด์และตัวคั่นขอบเขตมาด้วยพร้อมกับไบต์ของไฟล์ เพราะฉะนั้นโควตาที่เหลือให้ไฟล์เดียวจึงน้อยกว่า 100 MiB อย่างเคร่งครัด ไฟล์ขนาด 104,857,600 ไบต์พอดีจะถูกปฏิเสธ

ข้อสุดท้ายคือจุดที่ภาคปฏิบัติพลาดง่ายที่สุด: curl -F เติมขอบเขตให้เอง การเทียบขนาดไฟล์กับเส้นนั้นจึงไม่มีทางตรง

เกินขีดจำกัดแล้วได้ 400 กับ bad_request

การตอบกลับเมื่อเกินขีดจำกัดไม่ใช้ 413 และไม่มีถ้อยคำเกี่ยวกับขนาดเลย ลองสร้างซ้ำด้วยบอดีที่เกินไป 1 ไบต์:

head -c 104857601 /dev/zero > /tmp/over.bin
curl -s -X POST "$API_BASE/api/v1/misc/compress-pdf" \
  -H "X-API-KEY: $API_KEY" \
  -F "fileInput=@/tmp/over.bin"
HTTP/1.1 400 Bad Request
content-type: application/problem+json

{ "code": "bad_request",
  "detail": "failed to read multipart field: Error parsing `multipart/form-data` request",
  "hint": "Fix request parameters or upload a valid PDF.",
  "status": 400,
  "title": "Bad Request",
  "type": "https://pdf123.xyz/developers/errors#bad_request" }

สามอย่างที่ต้องอ่านประกอบกัน:

  • สถานะคือ 400 การอ่านบอดีล้มเหลวถูกจัดเป็น bad_request ที่นี่ และยังผ่าน problem+json ตามปกติ ไคลเอนต์ที่เขียนไว้สำหรับ "เกินขีดจำกัดหมายถึง 413" จึงเลือกทางผิด
  • code คือ bad_request ซึ่งเป็นรายการจริงในตารางรหัสข้อผิดพลาด มันไม่ตกลงไปในทางสำรอง แต่ใช้รหัสร่วมกับชื่อฟิลด์ที่พิมพ์ผิดหรือการเข้ารหัส multipart ที่พัง และไม่มีรายการใดในตารางนั้นเกี่ยวกับขนาด
  • hint บอกให้อัปโหลด PDF ที่ถูกต้อง ไฟล์ที่คุณอัปโหลดมีแนวโน้มสูงว่าเป็น PDF ที่ถูกต้อง ซึ่งบังเอิญใหญ่เกินไปไม่กี่ร้อยไบต์

สัญญาณบอกใบ้จึงไม่ใช่รหัสสถานะ แต่เป็นจำนวนไบต์ของบอดี: เมื่อได้ 400 ที่ detail มี failed to read multipart field ให้วัดขนาดต่อ ไม่ต้องย้อนไปตรวจฟอร์ม

413 เกิดขึ้นจริงบนเว็บนี้ เพียงแต่ไม่เกิดบนเอนด์พอยต์ของโอเปอเรชัน ทุกจุดเข้าที่รับอัปโหลดไฟล์ถูกยกเป็น 100 MiB ส่วนเอนด์พอยต์ที่ไม่รับอัปโหลดยังใช้ค่าเริ่มต้น 2 MiB ของเฟรมเวิร์ก HTTP (axum ของ Rust) ซึ่งบอดีที่เกินขีดจำกัดจะได้ 413 กับข้อความล้วนหนึ่งบรรทัด:

head -c 2097153 /dev/zero > /tmp/big.json
curl -s -w '\n%{http_code}\n' -X POST "$API_BASE/api/v1/auth/login" \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/big.json
Failed to buffer the request body: length limit exceeded
413

ข้อเท็จจริงเดียว ให้รหัสสถานะสองแบบและบอดีตอบกลับสองแบบ ขึ้นกับชนิดของเอนด์พอยต์ การยกประสบการณ์จากฝั่งหนึ่งไปอีกฝั่งจะทำให้เข้าใจผิด

ความล้มเหลวอีกแบบที่ใช้ตัวเลขเดียวกัน ทางขากลับ

คำขอที่มี Idempotency-Key จะแคชการตอบกลับไว้เพื่อให้การลองใหม่เล่นซ้ำได้ การแคชหมายถึงอ่านบอดีของการตอบกลับเข้าหน่วยความจำก่อน และการอ่านนั้นถูกจำกัดด้วย 100 MiB เดียวกัน แม้จะเกิดภายใต้เงื่อนไขที่แคบกว่ามาก:

  1. คำขอพา Idempotency-Key มา
  2. แคชพลาด คีย์นี้จึงเป็นคีย์ใหม่
  3. โอเปอเรชันต้นทางตอบ 2xx

การตอบกลับที่ล้มเหลวไม่ถูกแคชและผ่านเลยออกไป เพราะฉะนั้นมีเพียงเอาต์พุตขนาดใหญ่ที่สำเร็จเท่านั้นที่มาถึงขีดจำกัดนี้

สิ่งที่เกิดขึ้นตรงนั้นคือประเด็นที่ควรจำ: คุณได้ 500 และไม่มีอะไรถูกเขียนลงแคช โอเปอเรชันทำงานไปแล้ว แต่ผู้เรียกกลับเห็นความล้มเหลว และเพราะไม่มีอะไรถูกแคช การลองใหม่จึงรันทุกอย่างซ้ำทั้งหมด คีย์ idempotency มีไว้กำจัดงานซ้ำ แต่กลับล้มเหลวพอดีในเวลาที่จำเป็นที่สุด และทำให้งานที่เสร็จแล้วดูเหมือนความผิดพลาดของเซิร์ฟเวอร์ แคชนี้อยู่ในหน่วยความจำของโปรเซสและไม่เคยเขียนลงดิสก์ รีสตาร์ทแล้วก็หายไป ส่วนความหมายดูได้ที่ Idempotency-Key: การลองใหม่ที่ปลอดภัยสำหรับงาน PDF

100 MiB ไม่ใช่ค่าตั้งของแพลตฟอร์มที่ปรับได้

ตัวเลขนี้เปลี่ยนไม่ได้ ไม่มีตัวแปรสภาพแวดล้อมใดเพิ่มหรือลดมันได้ทั้งสองทาง การจะได้ตัวเลขอื่นต้องแก้โค้ดและรีบิลด์อิมเมจ ถ้าไปหามันในฐานะค่าตั้งของการดีพลอยจะไม่เจอ

มันยังมากกว่าโควตาข้อหนึ่ง ไบต์ของบอดีคำขอถูกอ่านเข้าหน่วยความจำทั้งหมดก่อนประมวลผล ทุกการอัปโหลดขนาดใหญ่ที่ทำพร้อมกันจึงถือหน่วยความจำจำนวนใกล้เคียงกันไว้ด้วย การยกเพดานขึ้นจึงหมายถึงการยอมรับจุดสูงสุดของหน่วยความจำที่สูงขึ้นตามมา: ตัวเลขนี้ยังเป็นสิ่งที่กันไม่ให้คำขอเดียวดึงโปรเซสลงไปด้วย

การดีพลอยแบบโฮสต์เองตามค่าเริ่มต้นไม่มีรีเวิร์สพร็อกซี และพอร์ทัลไม่ตรวจขนาดก่อนส่ง เพราะฉะนั้นการปฏิเสธนั้นมาจากขีดจำกัดของเซิร์ฟเวอร์เอง ถ้าวาง nginx ไว้ข้างหน้า จะชน nginx ก่อน: client_max_body_size ปล่อยผ่านเพียง 1 MiB โดยค่าเริ่มต้นและตอบ 413 ซึ่งรูปร่างใกล้เคียงกับที่เทียบไว้ข้างบนและเข้าใจผิดได้ง่ายว่าเป็นขีดจำกัดเดียวกัน

ทำอย่างไรเมื่อเจอเข้า

เริ่มจากวิธีที่ถูกที่สุดก่อน:

  1. วัดก่อนส่ง เทียบจำนวนไบต์ของบอดีคำขอกับ 104,857,600 ก่อนที่คำขอจะออกไป และเผื่อที่ว่างให้ขอบเขตด้วย วิธีนี้ดีกว่าการไปอ่านรหัสสถานะทีหลัง
  2. บีบอัดไฟล์ให้ต่ำกว่าขีดจำกัด ขนาดของไฟล์สแกนมาจากชั้นภาพเป็นส่วนใหญ่ และการบีบอัดใหม่มักตัดออกได้เป็นสัดส่วนที่เห็นได้ชัด บีบอัด PDF รันในเบราว์เซอร์ ไม่ต้องเขียนสคริปต์
  3. แบ่งงานออกเป็นหลายคำขอ เมื่อเนื้อหาแบ่งได้ แยก PDF แล้วส่งเป็นคำขอสั้น ๆ ไม่กี่คำขอ: ยุ่งยากน้อยกว่าการยกเพดาน และไม่ดันหน่วยความจำที่คำขอเดียวถืออยู่ให้สูงขึ้น
  4. เปลี่ยนขีดจำกัดเฉพาะเมื่อจำเป็นต้องส่งในคำขอเดียวจริง ๆ นั่นหมายถึงแก้โค้ดและรีบิลด์ พร้อมยอมรับค่าใช้จ่ายด้านหน่วยความจำจากหัวข้อก่อนหน้า

ขีดจำกัดนี้ให้ไคลเอนต์ตัดสินใจล่วงหน้าเอง

ความล้มเหลวทั้งสองแบบชี้ไปที่ข้อสรุปเดียว: ไคลเอนต์ต้องคำนวณตัวเลข 100 MiB เองก่อนส่ง ทางขาเข้า คุณได้รับการตอบเป็น bad_request ซึ่งเป็นรหัสที่ไม่บอกอะไรเกี่ยวกับขนาด ทางขาออก ตอบด้วย 500 ซึ่งดูเหมือนความผิดพลาดของเซิร์ฟเวอร์ การนับไบต์ก่อนที่คำขอจะออกไปคือวิธีตัดสินเดียวที่ไม่ต้องพึ่งว่าข้อความข้อผิดพลาดพูดว่าอะไร

Open tool
Process in the browser — no watermark, files removed after the job.
Open tool
Read next
ไฟล์เปิดไม่ได้: Get Info ก่อน ค่อย Repair แล้วหยุดเดา
เมื่อ PDF เปิดไม่ได้ ให้รัน Get Info เพื่อ preflight แล้ว Repair เพื่อสร้างโครงสร้างใหม่ นั่นคือการกู้ xref ไม่ใช่การโคลน Recovery Toolbox เดสก์ท็อป
แปลง PDF เป็น JPG หรือ PNG: DPI เปลี่ยนอะไร และส่งออกหน้าเดียวอย่างไร
PDF เป็นภาพ เรนเดอร์ทุกหน้าลงไฟล์ ZIP เป็น PNG เว้นแต่คุณเลือก JPEG ฟอร์มบนเบราว์เซอร์มีเพียงรูปแบบและ DPI ฟิลด์ API สำหรับเลือกหน้าและ WebP ไม่มีผล ขนาดไฟล์ที่วัดได้ที่ 150 และ 300 DPI และวิธีส่งออกเพียงหน้าเดียว
ส่งออกตารางว่าง (204): PDF ของคุณน่าจะไม่มีคอลัมน์
PDF to Excel และ PDF to CSV คืน HTTP 204 เมื่อไม่พบบล็อกตาราง ตั้งใจให้เป็นอย่างนั้น ไม่ใช่การล้มเหลว ควร OCR สแกนก่อน ส่วน PDF ที่มีแต่ร้อยแก้วจะยังว่างอยู่