You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Web App容器Nginx代理大文件上传超时问题求助

问题描述

将包含Nginx服务器与RClone的容器部署到Azure Web App for Containers实例中,Nginx反向代理通过auth_request指令验证请求后,将请求proxy_pass至本地的RClone上游服务器。受网络延迟/带宽影响,耗时超约5分钟的大文件上传会被取消,日志显示连接被Azure中间件中断。


环境配置

Nginx超时配置(/etc/nginx/conf.d/timeout.conf)

client_header_timeout 1800;
client_body_timeout 1800;
proxy_connect_timeout 1800;
proxy_send_timeout 1800;
proxy_read_timeout 1800;
send_timeout 1800;

Nginx主配置(/etc/nginx/nginx.conf)

pid                 /var/run/nginx/nginx.pid;
load_module         modules/ngx_http_js_module.so;
worker_processes    auto;

events {
    worker_connections 1024;
}

http {
    resolver                127.0.0.11 ipv6=off;
    resolver_timeout        10s;

    default_type            application/json;
    keepalive_timeout       65;
    client_max_body_size    0;
    
    upstream rclone {
      server localhost:5572;
    }

    upstream validator {
      server localhost:8079;
    }

    js_path "/etc/nginx/njs/";
    js_import main from index.js;

    server {
        listen                      8000;
        listen                      [::]:8000;
        server_name                 localhost;

        sendfile                    on;
        client_header_buffer_size   32k;

        location / {
            access_log off;
            return 200;
        }

        location /healthcheck {
            access_log off;
            return 200;
        }

        location ~* /operations/uploadfile {
            limit_except                HEAD POST { deny all; }
            auth_request                /_validate;

            proxy_set_header            Content-Length $content_length;
            proxy_set_header            Host $host;
            proxy_set_header            Referer $http_referer;
            proxy_set_header            X-Real-IP $remote_addr;
            proxy_set_header            X-Forwarded-Host $host;
            proxy_set_header            X-Forwarded-Server $host;
            proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

            proxy_buffering             off;
            proxy_request_buffering     off;
            proxy_intercept_errors      off;

            proxy_pass                  http://rclone;
        }       

        location = /_validate {
            internal;

            proxy_set_header        Content-Length "";
            proxy_set_header        X-Original-URI $request_uri;
            proxy_set_header        X-Original-Method $request_method;

            proxy_pass_request_body off;
            proxy_intercept_errors  off;

            proxy_pass              http://validator/validate;            
        }

        error_page 405 = @405;
        location @405 { return 405 '{"status":405,"code":"MethodNotAllowed","message":"Method Not Allowed"}\n'; } 

        error_page 500 = @500;
        location @500 { return 500 '{"status":500,"code":"InternalServerError","message":"Internal Server Error"}\n'; }   
    }
        
    server {
        listen              8079;
        listen              [::]:8079;
        server_name         localhost;

        client_header_buffer_size   32k;

        location /validate {
            js_content                      main.authorize;
            js_fetch_timeout                10;
            js_fetch_trusted_certificate    /etc/ssl/certs/ca-certificates.crt;
        }
    }
}

测试命令

Curl脚本

#!/bin/bash

curl -v -X POST 'https://<redacted>.azurewebsites.net/operations/uploadfile?<rclone_query_params>' \
  -H @token.txt \
  -F file="../samples/test-500MB.file"

JavaScript上传脚本

const fs = require('fs');
const axios = require('axios');

const domain = 'https://<redacted>.azurewebsites.net';
const file = '../samples/test-500MB.file';
const fileStream = fs.createReadStream(file);
const token = fs.readFileSync('./token.txt', 'utf8').split(':')[1].trim();

console.log(`Uploading file: ${file}`);
console.log(`Token: ${token}`);

axios({
  method: 'post',
  url: `${domain}/operations/uploadfile?<rclone_query_params>`,
  headers: {
    'Content-Type': 'application/octet-stream',
    'Content-Length': fs.statSync(file).size,
    Expect: '100-continue',
    Connection: 'keep-alive',
    'Transfer-Encoding': 'chunked',
    'User-Agent': 'axios/0.21.4',
    Authorization: `${token}`
  },
  data: fileStream,
  maxContentLength: Infinity,
  maxBodyLength: Infinity,
  onUploadProgress: (progressEvent) => {
    const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
    console.log(`Upload progress: ${percentCompleted}%`);
  },
  validateStatus: (status) => {
    return (status >= 200 && status < 300) || status === 308;
  },
  maxRedirects: 0
})
  .then((response) => {
    console.log(`Upload completed: ${response.status} ${response.statusText}`);
  })
  .catch((error) => {
    console.error(`Upload failed: ${error.message}`);
  });

错误日志

Nginx日志

2023/05/13 13:01:34 [info] 18#18: *15 client prematurely closed connection while sending request to upstream, client: <redacted>, server: localhost, request: "POST /uploadfile?<rclone_query_param> HTTP/1.1", upstream: "http://127.0.0.1:5572/operations/uploadfile?<rclone_query_param>", host: "<redacted>.azurewebsites.net"

RClone日志

2023/05/13 13:01:34 ERROR : rc: "operations/uploadfile": error: multipart upload failed to upload part: context canceled

Azure中间件日志

Failed to forward request to http://<redacted>. Encountered a System.Threading.Tasks.TaskCanceledException exception after 299998.262ms with message: The request was canceled due to the configured HttpClient.Timeout of 300 seconds elapsing.. Check application logs to verify the application is properly handling HTTP traffic.

解决思路

  1. 调整Azure Web App请求超时限制

    • Azure Web App默认300秒请求超时,需在门户的Web App配置中添加应用设置WEBSITES_CONTAINER_START_TIME_LIMIT,设置为更大值(如1800秒);同时确认WEBSITES_PORT与容器暴露端口(8000)一致。
    • 使用Azure CLI修改:
      az webapp config appsettings set --name <your-webapp-name> --resource-group <your-resource-group> --settings WEBSITES_CONTAINER_START_TIME_LIMIT=1800
      
  2. 优化Nginx长连接配置

    • 在/operations/uploadfile的location块中添加HTTP/1.1长连接支持:
      location ~* /operations/uploadfile {
          # 原有配置保留
          proxy_http_version 1.1;
          proxy_set_header Connection "";
      }
      
  3. 延长RClone RC服务超时

    • 启动RClone时添加--rc-timeout参数,确保服务不会提前断开:
      rclone rcd --rc-addr :5572 --rc-timeout 1800s <其他启动参数>
      
  4. 客户端侧优化

    • Curl命令添加--no-buffer参数,避免数据缓冲导致超时:
      curl -v --no-buffer -X POST 'https://<redacted>.azurewebsites.net/operations/uploadfile?<rclone_query_params>' \
        -H @token.txt \
        -F file="../samples/test-500MB.file"
      
  5. 启用ARR Affinity(多实例场景)

    • 在Azure门户Web App配置中开启"ARR Affinity",确保长请求始终路由到同一实例,避免实例切换导致连接中断。

内容的提问来源于stack exchange,提问作者chauvd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 01:40:04