Назад | Перейти на главную страницу

nginx proxy_pass, повреждает файл pdf при передаче?

У меня очень неприятная проблема, а PDF-файлы, которые я пытаюсь загрузить с сайта, испорчены. Они генерируются нормально (я вижу, что если я загружу его через SFTP из временной папки, они будут помещены в него).

    location ~ \.cgi$ {
        #try_files $uri =404;
        gzip off;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:8181;
    }

Код Perl довольно прост (я не буду также вставлять код генерации PDF, так как он работает нормально);

my $filepath = qq|/home/fatpeter/web/site.com/cgi-bin/hotels/admin/tmp_pdf/| . CORE::time() . q|.pdf|;

$pdf->to_file($filepath);

$file_name =~ s/\-/_/sig;
my $size = -s $filepath;

my $file = \do { local *FH; *FH };
open $file, "<$filepath" or die "Unable to open file '$filepath': $!";
binmode $file;
binmode STDOUT;

print $IN->header($IN->file_headers(
    filename => $file_name,
    mimetype => 'application/pdf',
    inline   => 0,
    size     => $size
));

{
    local $\;
    while (read($file, my $chunk, 4096)) {
        print $chunk;
    }
}

Таким образом, в основном nginx передает запрос Apache2.4, затем запускается Perl и создает PDF-файл. Затем скрипт возвращает им PDF-файл.

[Вт, 25 апреля, 13:41: 36.810922 2017] [: ошибка] [pid 2901]: Apache2 IO write: (104) Сброс соединения одноранговым узлом на /home/fatpeter/web/site.com/cgi-bin/hotels/invoices .cgi строка 285

Строка 285 - это while () { } цикл:

    while (read($file, my $chunk, 4096)) {

Я не понимаю, почему он отключал его до загрузки. Любые идеи? Как бы то ни было, размер тестового файла, который я использую, составляет 363 КБ (372 596 байт), так что он не очень большой! Мои настройки прокси в основном nginx.conf файлы:

proxy_redirect выключен; proxy_set_header Host $ host; proxy_set_header X-Real-IP $ remote_addr; proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for; proxy_pass_header Set-Cookie; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffers 32 4k;

Это то, что скрипт отправляет в виде заголовков:

Content-type: application/pdf
Content-Disposition: attachment; filename="foo.pdf"; size=372596
Content-Length: 372596

ОБНОВИТЬ: Интересно, что теперь я получаю это сообщение об ошибке в Firefox при загрузке:

C: \ Users \ Andy \ AppData \ Local \ Temp \ Jy4tj5pr.pdf.part не может быть сохранен, так как исходный файл не может быть прочитан.

Повторите попытку позже или обратитесь к администратору сервера.

Я также теперь вижу это в журнале доступа:

127.0.0.1 - - [25/Apr/2017:15:29:38 +0000] "GET /cgi-bin/hotels/invoices.cgi?action=download;id=60d90acf677e9c81;invoice=1055;t=french HTTP/1.0" 200 372861 "https://www.example.com/cgi-bin/hotels/invoices.cgi?t=french" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"
81.174.134.133 - - [25/Apr/2017:15:29:38 +0000] "GET /cgi-bin/hotels/invoices.cgi?action=download;id=60d90acf677e9c81;invoice=1055;t=french HTTP/2.0" 200 372616 "https://www.example.com/cgi-bin/hotels/invoices.cgi?t=french" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0"

ОБНОВЛЕНИЕ 3: Хорошо, поэтому я подхожу немного ближе. Проблема, похоже, связана с "фрагментированием" в сценарии:

while (read($file, my $chunk, 4096)) {

Если я изменю это, например, на:

while (read($file, my $chunk, 409600)) {

(больше, чем размер рассматриваемого файла), он РАБОТАЕТ! Но проблема в том, что мне делать с большими файлами?

Итак, вот рабочий код:

{
    local $\;
    while (read($file, my $chunk, -s $filepath)) {
        print $chunk;
    }
}

Мне просто не нравится мысль о невозможности отправлять его блоками. Есть ли недостатки в том, чтобы делать это таким образом?