nginx tải lên vấn đề client_max_body_size


117

Tôi đang chạy nginx / ruby-on-rails và tôi có một biểu mẫu nhiều phần đơn giản để tải tệp lên. Mọi thứ hoạt động tốt cho đến khi tôi quyết định hạn chế kích thước tối đa của các tệp mà tôi muốn tải lên. Để làm điều đó, tôi đặt nginx client_max_body_sizethành 1m (1MB) và mong đợi trạng thái HTTP 413 (Đối tượng yêu cầu quá lớn) để phản hồi khi quy tắc đó bị phá vỡ.

Vấn đề là khi tôi tải lên tệp 1,2 MB, thay vì hiển thị trang lỗi HTTP 413, trình duyệt bị treo một chút và sau đó chết với thông báo "Kết nối đã được đặt lại trong khi trang đang tải".

Tôi đã thử tất cả các tùy chọn mà nginx cung cấp, dường như không có gì hoạt động. Có ai có bất kỳ ý tưởng về điều này?

Đây là nginx.conf của tôi:

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;    
    }    
}

Cảm ơn.


**Edit**

Môi trường / UA: Windows XP / Firefox 3.6.13

Câu trả lời:


128

nginx "không nhanh" khi máy khách thông báo rằng nó sẽ gửi một phần thân lớn hơn client_max_body_sizebằng cách gửi phản hồi 413 và đóng kết nối.

Hầu hết khách hàng không đọc phản hồi cho đến khi toàn bộ nội dung yêu cầu được gửi đi. Vì nginx đóng kết nối, máy khách sẽ gửi dữ liệu đến ổ cắm đã đóng, gây ra TCP RST.

Nếu ứng dụng khách HTTP của bạn hỗ trợ nó, cách tốt nhất để xử lý điều này là gửi một Expect: 100-Continuetiêu đề. Nginx hỗ trợ này một cách chính xác như của 1.2.7, và sẽ trả lời với một 413 Request Entity Too Largecâu trả lời hơn là 100 Continuenếu Content-Lengthvượt quá kích thước cơ thể tối đa.


1
Ồ, tôi nên chỉ ra rằng câu trả lời này giả định rằng khách hàng đang gửi Content-Lengthhơn là gửi Transfer-Encoding: chunked.
Joe Shaw

2
Tuy nhiên, tác giả nginx đã đăng một bản vá để sửa lỗi này trên danh sách gửi thư: nginx.2469901.n2.nabble.com/…. Không biết liệu nó có được thêm vào nhánh ổn định 1.2.x hay không.
Joe Shaw

Cảm ơn, điều đó thực sự giải thích rất nhiều. Chắc chắn có vẻ như Expectlà cách để đi cho các yêu cầu lớn.
krukid

Cập nhật câu trả lời của tôi để lưu ý rằng bản vá mà tôi đã đề cập trước đó đã được cam kết và kết hợp vào bản phát hành 1.2.7.
Joe Shaw

Chỉ để tiết kiệm thời gian của tìm kiếm một cú pháp đẹp (như tôi đã dành): request.setHeader(HttpHeaders.EXPECT, CONTINUE);với import org.apache.http.HttpHeaders;import static org.jboss.netty.handler.codec.http.HttpHeaders.Values.CONTINUE;
Erez Cohen

48

Tải lên của bạn có chết ở cuối cùng không? 99% trước khi bị rơi? Phần thân máy khách và bộ đệm là chìa khóa vì nginx phải đệm dữ liệu đến. Phần thân cấu hình (dữ liệu của phần thân yêu cầu) chỉ định cách nginx xử lý luồng dữ liệu nhị phân số lượng lớn từ các ứng dụng khách nhiều phần thành logic của ứng dụng của bạn.

Các cleangiải phóng lập giới hạn bộ nhớ và tiêu thụ bằng cách hướng dẫn nginx để lưu trữ đệm đến trong một tập tin và sau đó làm sạch tập tin này sau đó từ đĩa bằng cách xóa nó.

Đặt body_in_file_onlyđể cleanvà điều chỉnh bộ đệm cho client_max_body_size. Cấu hình của câu hỏi ban đầu đã được bật sendfile, hãy tăng thời gian chờ. Tôi sử dụng các cài đặt bên dưới để khắc phục sự cố này, thích hợp trên các ngữ cảnh cấu hình, máy chủ & http cục bộ của bạn.

client_body_in_file_only clean;
client_body_buffer_size 32K;

client_max_body_size 300M;

sendfile on;
send_timeout 300s;

Ngay cả khi điều này dẫn đến việc nginx trả về HTTP 413 thích hợp, UA vẫn sẽ gửi toàn bộ nội dung yêu cầu, phải không? Trong trường hợp đó, tôi nghĩ nên thử cách tiếp cận mà @ joe-shaw đề xuất.
krukid

@krukid khi có vẻ như chúng tôi đã tải lên xong 99% trước khi NGINX "không thành công nhanh", tôi đồng ý với bạn. Trong trường hợp này, tất cả các dấu hiệu đều tích cực xung quanh đối tượng yêu cầu, tức là chẩn đoán là logic ứng dụng máy chủ nội bộ vẫn ổn - bất cứ điều gì chạy sau Nginx. Vì vậy, mặc dù có khả năng yêu cầu đã được hình thành tốt, nhưng nhu cầu của chúng ta sau đó là xem xét lý do tại sao NGINX lại ngừng phản hồi. client_max_body_size nên là tùy chọn cấu hình đầu tiên mà chúng tôi xem xét, sau đó xem xét các bộ đệm, bởi vì với một tải lên đủ lớn, giải pháp chính xác phụ thuộc vào dung lượng bộ nhớ mà máy chủ của chúng tôi có thể xử lý.
Bent Cardan

@Bent Cardan. Cách tiếp cận này dường như là cách tốt hơn và tôi đã thử nó. Nhưng tôi vẫn gặp lỗi 413 sau khoảng 20 giây đối với tệp 4mb. Tốc độ tăng tốc của tôi không thể quản lý 4 MB trong 20 giây, do đó, nó đang xảy ra sau khi dữ liệu đã chảy khá lâu. Suy nghĩ?
Jerome

Tôi đã thêm các thay đổi trong tệp nginx.conf _client_max_body_size 300M; sendfile trên; send_timeout 300 giây; _ Nó hoạt động hoàn hảo cho tôi Cảm ơn
Ramesh Chand

Giải pháp phù hợp với tôi openshift php7 nginx.
marlo

7

Từ tài liệu :

Cần phải nhớ rằng các trình duyệt không biết làm thế nào để hiển thị chính xác lỗi này.

Tôi nghi ngờ đây là những gì đang xảy ra, nếu bạn kiểm tra HTTP to-and-fro bằng các công cụ như Firebug hoặc Live HTTP Headers (cả hai phần mở rộng của Firefox), bạn sẽ có thể biết điều gì đang thực sự xảy ra.


1
Tôi cũng đã gặp điều đó ở đây: forum.nginx.org/read.php?2,2620 Trong đó tác giả nginx nói rằng mọi người có thể thử thay đổi lingering_time / lingering_timeout - cả hai đều không có tác dụng trong trường hợp của tôi. Bên cạnh đó, tôi không hiểu làm thế nào có thể xảy ra vấn đề thời gian chờ liên tục khi tôi đang tải lên tệp 1,2MB với giới hạn 1MB dễ dàng có kết nối 5Mbps ổn định. Tôi đã đánh hơi thấy phản hồi và nó gửi trang 413 với tiêu đề "Kết nối: đóng", nhưng kết nối dường như không đóng.
krukid

Tôi đoán rằng tôi chỉ có một thời gian khó tin rằng mặc dù có trạng thái HTTP 413 hoàn toàn hợp lệ, nó không kích hoạt trong trình duyệt. Tôi đã truy cập vào rất nhiều nơi mà mọi người không thể thoát khỏi trang đó và thậm chí tôi chưa bao giờ nhìn thấy nó.
krukid

Nếu bạn vô hiệu hóa hành khách, nó có đóng kết nối không?
Mark Rose

Tôi đã so sánh các câu trả lời có và không có hành khách. Khi mọi thứ chạy bình thường và tôi tải lên một tệp lớn hơn nhiều lần (~ 14MB) so với giới hạn 1MB của mình, tôi nhận được 413 phản hồi nhiều lần (vì ứng dụng khách liên tục gửi các khối) và "Đặt lại kết nối" cuối cùng trông giống như hết thời gian chờ. Nếu không có hành khách, tôi nhận được một phản hồi tức thì 413 và tất cả tiến trình dừng lại, nhưng tôi vẫn thấy trang "Đặt lại kết nối", không phải trang 413.html tĩnh của tôi hoặc bất kỳ thứ gì ngụ ý "Thực thể quá lớn"
krukid
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.