nginx อัปโหลดปัญหา client_max_body_size


117

ฉันใช้ nginx / ruby-on-rail และฉันมีรูปแบบหลายส่วนง่ายๆในการอัปโหลดไฟล์ ทุกอย่างทำงานได้ดีจนกว่าฉันจะตัดสินใจ จำกัด ขนาดไฟล์สูงสุดที่ฉันต้องการอัปโหลด ในการทำเช่นนั้นฉันตั้งค่า nginx client_max_body_sizeเป็น1m (1MB) และคาดว่าจะมีสถานะ HTTP 413 (Request Entity Too Large) ในการตอบสนองเมื่อกฎนั้นแตก

ปัญหาคือเมื่อฉันอัปโหลดไฟล์ 1.2 MB แทนที่จะแสดงหน้าข้อผิดพลาด HTTP 413 เบราว์เซอร์จะแฮงค์เล็กน้อยจากนั้นก็ตายพร้อมกับข้อความ "การเชื่อมต่อถูกรีเซ็ตในขณะที่หน้ากำลังโหลด"

ฉันได้ลองทุกตัวเลือกที่ nginx เสนอดูเหมือนจะไม่มีอะไรทำงาน ใครมีความคิดเกี่ยวกับเรื่องนี้หรือไม่?

นี่คือ nginx.conf ของฉัน:

worker_processes  1;
timer_resolution  1000ms;
events {
    worker_connections  1024;
}

http {
    passenger_root /the_passenger_root;
    passenger_ruby /the_ruby;

    include       mime.types;
    default_type  application/octet-stream;

    sendfile           on;
    keepalive_timeout  65;

    server {
      listen 80;
      server_name www.x.com;
      client_max_body_size 1M;
      passenger_use_global_queue on;
      root /the_root;
      passenger_enabled on;

      error_page 404 /404.html;
      error_page 413 /413.html;    
    }    
}

ขอบคุณ


**Edit**

สภาพแวดล้อม / UA: Windows XP / Firefox 3.6.13

คำตอบ:


128

nginx "ล้มเหลวอย่างรวดเร็ว" เมื่อไคลเอนต์แจ้งว่ากำลังจะส่งเนื้อหาที่ใหญ่กว่าclient_max_body_sizeโดยส่งการตอบกลับ 413 และปิดการเชื่อมต่อ

ลูกค้าส่วนใหญ่จะไม่อ่านคำตอบจนกว่าจะส่งเนื้อหาคำขอทั้งหมด เนื่องจาก nginx ปิดการเชื่อมต่อไคลเอนต์จึงส่งข้อมูลไปยังซ็อกเก็ตปิดทำให้เกิด TCP RST

หากไคลเอ็นต์ HTTP ของคุณรองรับวิธีที่ดีที่สุดในการจัดการสิ่งนี้คือการส่งExpect: 100-Continueส่วนหัว Nginx สนับสนุนนี้อย่างถูกต้องเป็นของ 1.2.7 และจะตอบกลับด้วย413 Request Entity Too Largeการตอบสนองมากกว่า100 Continueถ้าContent-Lengthเกินกว่าขนาดของร่างกายสูงสุด


1
โอ้ฉันควรจะชี้ให้เห็นว่าคำตอบนี้อนุมานว่าลูกค้าจะส่งมากกว่าการทำContent-Length Transfer-Encoding: chunked
Joe Shaw

2
ผู้เขียน nginx โพสต์แพตช์เพื่อแก้ไขปัญหานี้ในรายชื่อส่งเมล: nginx.2469901.n2.nabble.com/… ไม่มีคำว่าจะถูกเพิ่มลงในสาขาที่เสถียร 1.2.x
Joe Shaw

ขอบคุณที่อธิบายได้มากมายจริงๆ ดูเหมือนว่าExpectเป็นวิธีที่จะส่งคำขอจำนวนมาก
krukid

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

เพียงเพื่อประหยัดเวลาในการค้นหาไวยากรณ์ที่ดี (เหมือนที่ฉันใช้ไป): request.setHeader(HttpHeaders.EXPECT, CONTINUE);ด้วยimport org.apache.http.HttpHeaders;และimport static org.jboss.netty.handler.codec.http.HttpHeaders.Values.CONTINUE;
Erez Cohen

48

การอัปโหลดของคุณตายในตอนท้ายหรือไม่ 99% ก่อนพัง? ตัวไคลเอ็นต์และบัฟเฟอร์เป็นกุญแจสำคัญเนื่องจาก nginx ต้องบัฟเฟอร์ข้อมูลขาเข้า การกำหนดค่าเนื้อหา (ข้อมูลของเนื้อหาคำขอ) ระบุวิธีที่ nginx จัดการการไหลของข้อมูลไบนารีจำนวนมากจากไคลเอนต์แบบหลายส่วนเข้าสู่ตรรกะของแอปของคุณ

การcleanตั้งค่านี้ช่วยเพิ่มขีด จำกัด หน่วยความจำและปริมาณการใช้โดยสั่งให้ nginx จัดเก็บบัฟเฟอร์ขาเข้าในไฟล์จากนั้นล้างไฟล์นี้ออกจากดิสก์ในภายหลังโดยการลบออก

ตั้งค่าbody_in_file_onlyการและปรับบัฟเฟอร์สำหรับclean client_max_body_sizeการกำหนดค่าของคำถามเดิมมีการส่งไฟล์อยู่แล้วเพิ่มระยะหมดเวลาด้วย ฉันใช้การตั้งค่าด้านล่างเพื่อแก้ไขปัญหานี้ซึ่งเหมาะสมกับบริบทการกำหนดค่าเซิร์ฟเวอร์และ http ภายในเครื่องของคุณ

client_body_in_file_only clean;
client_body_buffer_size 32K;

client_max_body_size 300M;

sendfile on;
send_timeout 300s;

แม้ว่าสิ่งนี้จะส่งผลให้ nginx ส่งคืน HTTP 413 ที่เหมาะสม แต่ UA จะยังคงส่งเนื้อหาคำขอทั้งหมดใช่หรือไม่ ในกรณีนี้ฉันคิดว่ามันคุ้มค่าที่จะลองแนวทางที่ @ joe-shaw แนะนำ
krukid

@krukid เมื่อดูแล้วเราอัปโหลดเสร็จ 99% ก่อนที่ NGINX จะ "ล้มเหลวเร็ว" ฉันเห็นด้วยกับคุณ ในกรณีนี้สัญญาณทั้งหมดเป็นบวกรอบ ๆ วัตถุที่ร้องขอกล่าวคือการวินิจฉัยคือตรรกะของแอปพลิเคชันเซิร์ฟเวอร์ภายในนั้นใช้ได้ไม่ว่าอะไรก็ตามที่ทำงานหลัง Nginx ดังนั้นในขณะที่เป็นไปได้ว่าคำขอจะเกิดขึ้นอย่างดีความจำเป็นของเราคือการพิจารณาว่าเหตุใด NGINX จึงตอบสนอง client_max_body_size ควรเป็นตัวเลือก config แรกที่เราดูจากนั้นพิจารณาบัฟเฟอร์เนื่องจากมีการอัปโหลดที่ใหญ่พอวิธีแก้ปัญหาที่ถูกต้องขึ้นอยู่กับหน่วยความจำที่เซิร์ฟเวอร์ของเราสามารถจัดการได้เช่นกัน
Bent Cardan

@ เบ็นท์คาร์ดาน. แนวทางนี้ดูเหมือนจะดีกว่าและฉันลองแล้ว แต่ฉันยังคงได้รับข้อผิดพลาด 413 หลังจากนั้นประมาณ 20 วินาทีสำหรับไฟล์ 4mb อัพสปีดของฉันไม่สามารถจัดการ 4 MB ใน 20 วินาทีได้ดังนั้นจึงเกิดขึ้นหลังจากที่ข้อมูลไหลไปไม่น้อย คิด?
เจอโรม

ฉันได้เพิ่มการเปลี่ยนแปลงในไฟล์ nginx.conf _client_max_body_size 300M; sendfile บน send_timeout 300s; _ มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันขอบคุณ
Ramesh Chand

openshift php7 nginxวิธีการแก้ปัญหาการทำงานสำหรับฉันใน
marlo

7

จากเอกสารประกอบ :

โปรดทราบว่าเบราว์เซอร์ไม่ทราบวิธีแสดงข้อผิดพลาดนี้อย่างถูกต้อง

ฉันสงสัยว่านี่คือสิ่งที่เกิดขึ้นหากคุณตรวจสอบ HTTP ไปมาโดยใช้เครื่องมือเช่นFirebugหรือLive HTTP Headers (ทั้งส่วนขยายของ Firefox) คุณจะสามารถเห็นสิ่งที่เกิดขึ้นจริง


1
ฉันเจอที่นี่เช่นกัน: forum.nginx.org/read.php?2,2620โดยที่ผู้เขียน nginx กล่าวว่าผู้คนสามารถลองเปลี่ยน lingering_time / lingering_timeout ซึ่งทั้งสองอย่างนี้ไม่มีผลในกรณีของฉัน นอกจากนี้ฉันไม่เห็นว่าจะมีปัญหาการหมดเวลาถาวรได้อย่างไรเมื่อฉันอัปโหลดไฟล์ 1.2MB ที่มีขีด จำกัด 1MB อย่างง่ายดายโดยมีการเชื่อมต่อ 5Mbps ที่สม่ำเสมอ ฉันได้ดมคำตอบแล้วมันส่งหน้า 413 พร้อมส่วนหัว "Connection: close" แต่ดูเหมือนว่าการเชื่อมต่อจะไม่ปิด
krukid

ฉันเดาว่าฉันคงยากที่จะเชื่อว่าแม้ว่าจะมีสถานะ HTTP 413 ที่ถูกต้องสมบูรณ์ แต่ก็ไม่ทำงานในเบราว์เซอร์ ฉันได้ไปหาสถานที่หลายแห่งที่ผู้คนไม่สามารถกำจัดเพจนั้นได้และฉันก็ไม่เคยเห็นมันด้วยซ้ำ
krukid

หากคุณปิดการใช้งานผู้โดยสารจะปิดการเชื่อมต่อหรือไม่?
Mark Rose

ฉันเปรียบเทียบคำตอบที่มีและไม่มีผู้โดยสาร เมื่อทุกอย่างทำงานตามปกติและฉันอัปโหลดไฟล์ที่มีขนาดใหญ่กว่าข้อ จำกัด 1MB หลายเท่า (~ 14MB) ฉันได้รับการตอบสนอง 413 หลายครั้ง (เนื่องจากไคลเอนต์ยังคงส่งชิ้นส่วน) และ "การรีเซ็ตการเชื่อมต่อ" ขั้นสุดท้ายดูเหมือนจะหมดเวลา หากไม่มีผู้โดยสารฉันจะได้รับการตอบกลับทันที 413 ครั้งและความคืบหน้าทั้งหมดหยุดลง แต่ฉันยังคงเห็นหน้า "การรีเซ็ตการเชื่อมต่อ" ไม่ใช่ 413.html แบบคงที่ของฉันหรืออะไรก็ตามที่บ่งบอกว่า "เอนทิตีใหญ่เกินไป"
krukid
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.