проблема загрузки nginx client_max_body_size

117

Я запускаю nginx / ruby-on-rails, и у меня есть простая составная форма для загрузки файлов. Все работает нормально, пока я не решу ограничить максимальный размер загружаемых файлов. Для этого я установил nginx client_max_body_sizeна 1 м (1 МБ) и ожидаю в ответ статус HTTP 413 (Request Entity Too Large), когда это правило нарушается.

Проблема в том, что когда я загружаю файл размером 1,2 МБ, вместо отображения страницы с ошибкой 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

krukid
источник

Ответы:

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.
Джо Шоу
2
Автор nginx разместил исправление для исправления этого в списке рассылки: nginx.2469901.n2.nabble.com/… Однако пока не известно, будет ли он добавлен в стабильную ветку 1.2.x.
Joe Shaw
Спасибо, это многое объясняет. Конечно, похоже, Expectэто способ справиться с большими запросами.
krukid
Обновил свой ответ, чтобы отметить, что упомянутый ранее патч был зафиксирован и включен в выпуск 1.2.7.
Джо Шоу
Просто чтобы сэкономить время на поиски хорошего синтаксиса (как я потратил): request.setHeader(HttpHeaders.EXPECT, CONTINUE);с import org.apache.http.HttpHeaders;иimport static org.jboss.netty.handler.codec.http.HttpHeaders.Values.CONTINUE;
Эрез Коэн
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 05
@krukid, когда кажется, что мы завершили загрузку на 99% до того, как NGINX "быстро откажет", я согласен с вами. В этом случае все признаки вокруг объекта запроса положительны, т. Е. Диагностика заключается в том, что логика внутреннего серверного приложения в порядке - независимо от того, что работает за Nginx. Таким образом, хотя вполне вероятно, что запрос был правильно сформирован, нам нужно рассмотреть, почему NGINX подавляется ответом. client_max_body_size должен быть первым параметром конфигурации, который мы рассмотрим, а затем рассмотрим буферы, потому что при достаточно большой загрузке правильное решение зависит от того, сколько памяти может обработать наш сервер.
Бент Кардан,
@ Согнутый кардан. Этот подход показался мне лучшим, и я попробовал его. Но я все еще получаю ошибку 413 примерно через 20 секунд для файла размером 4 МБ. Мои повышения скорости не могут справиться с 4 МБ за 20 секунд, поэтому это происходит после того, как данные были переданы довольно долго. Мысли?
Джером
Я добавил изменения в файл nginx.conf _client_max_body_size 300M; sendfile on; send_timeout 300 с; _ Он отлично работает для меня Спасибо
Рамеш Чанд
У меня решение работает openshift php7 nginx.
Марло
7

Из документации :

Необходимо учитывать, что браузеры не умеют корректно отображать эту ошибку.

Я подозреваю, что это именно то, что происходит, если вы проверяете HTTP туда-сюда с помощью таких инструментов, как Firebug или Live HTTP Headers (оба расширения Firefox), вы сможете увидеть, что происходит на самом деле.

ZoFreX
источник
1
Я также наткнулся на это здесь: forum.nginx.org/read.php?2,2620 Где автор nginx говорит, что люди могут попробовать изменить lingering_time / lingering_timeout - и то, и другое не повлияло на мой случай. Кроме того, я просто не понимаю, как может возникнуть постоянная проблема с тайм-аутом, когда я загружаю файл размером 1,2 МБ с ограничением в 1 МБ, легко имея стабильное соединение 5 Мбит / с. Я понюхал ответ, и он отправил страницу 413 с заголовком «Connection: close», но соединение, похоже, не закрывается.
krukid
Я думаю, мне просто трудно поверить в то, что, хотя есть совершенно допустимый HTTP-статус 413, он не срабатывает в браузерах. Я искал в Google много мест, где люди не могут избавиться от этой страницы, и я даже не видел ее.
krukid
Если отключить пассажира, закрывает ли он соединение?
Марк Роуз
Ну я сравнил отзывы с пассажиром и без него. Когда все работает нормально и я загружаю файл в несколько раз больше (~ 14 МБ), чем мое ограничение в 1 МБ, я получаю 413 ответов несколько раз (потому что клиент продолжает отправлять фрагменты), и окончательный «сброс соединения» действительно выглядит как тайм-аут. Без пассажира я получаю один мгновенный ответ 413, и весь прогресс останавливается, но я все еще вижу страницу «Сброс подключения», а не свой статический 413.html или что-то еще, что подразумевает «Entity Too Large»
krukid