nginx 客户端关闭连接

问题描述

我有一个完全 dockerised 的应用程序:

  • Nginx 作为代理
  • 后端服务器 (express.js)
  • 一个数据库(mongodb)
  • 前端服务器(express js)
  • goaccess 用于日志记录

问题是当我使用 POST 请求访问我的后端端点时,响应永远不会发送到客户端。 Nginx 记录了 499 代码以及此日志

 epoll_wait() reported that client prematurely closed connection,so upstream connection is closed too while sending request to upstream,

客户端就是浏览器,这是毫无疑问的。

在 Firefox 中处理 1 分钟后和在 chrome 中处理 5 分钟后出现错误。据我所知,这些时间与这些浏览器的超时设置相匹配。我可以在 Firefox 中增加超时时间,但这不是一个可行的解决方案。

当我摆脱代理时,请求完成并且客户端在大约 15 分钟内得到响应。所以我觉得是Nginx配置有问题,但不知道是什么。

到目前为止,我试图增加您可以想象的所有超时时间,但这并没有改变任何东西。 我也尝试在 Nginx 中设置 proxy_ignore_client_abort 但在我的情况下它没有用。确实,Nginx 和我的后端之间的连接仍然有效,请求在 15 分钟后完成(Nginx 日志中的代码 200)但 ui 未更新,因为客户端已终止与 Nginx 的连接。

我认为浏览器认为Nginx已经死了,因为它没有收到任何数据,所以关闭了TCP连接。
我稍后会尝试在请求仍在处理时通过在我的网站页面之间切换来“刺激”这个 TCP 连接(因此浏览器不应该关闭连接),但是如果我必须做一些奇怪的事情来获得我的后端结果,这不是一个可行的解决方案。

应该有一种方法可以处理长请求而不会面临这些浏览器的超时,但我不知道如何。 任何帮助将不胜感激:)

我的Nginx配置:

user                    Nginx;
pid                     /run/Nginx.pid;
worker_processes        auto;
worker_rlimit_nofile    65535;

events {
    multi_accept        on;
    worker_connections  65535;
}

http {
    charset                 utf-8;
    sendfile                on;
    tcp_nopush              on;
    tcp_nodelay             on;
    server_tokens           off;
    log_not_found           off;
    types_hash_max_size     2048;
    types_hash_bucket_size  64;
    client_max_body_size    16M;

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

    # logging
    log_format my_log   '$remote_addr - $remote_user [$time_local] "$request" '
                            '$status $body_bytes_sent "$http_referer" '
                            '"$http_user_agent" "$http_x_forwarded_for" ';

    access_log              /var/log/Nginx/access.log my_log;
    error_log               /var/log/Nginx/error.log info;

    # limits
    limit_req_log_level     warn;
    limit_req_zone          $binary_remote_addr zone=main:10m rate=10r/s;

    # SSL
    ssl_session_timeout     1d;
    ssl_session_cache       shared:SSL:10m;
    ssl_session_tickets     off;

    # Mozilla Intermediate configuration
    ssl_protocols           TLSv1.2 TLSv1.3;
    ssl_ciphers             ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-poly1305:ECDHE-RSA-CHACHA20-poly1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

    # OCSP
    ssl_stapling            on;
    ssl_stapling_verify     on;
    resolver                1.1.1.1 1.0.0.1 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
    resolver_timeout        2s;

    # Connection header for WebSocket reverse proxy
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ""      close;
    }

    map $remote_addr $proxy_forwarded_elem {

        # IPv4 addresses can be sent as_is
        ~^[0-9.]+$          "for=$remote_addr";

        # IPv6 addresses need to be bracketed and quoted
        ~^[0-9A-Fa-f:.]+$   "for\"[$remote_addr]\"";

        # Unix domain socket names cannot be represented in RFC 7239 Syntax
        default             "for=unkNown";
    }

    map $http_forwarded $proxy_add_forwarded {

        # If the incoming Forwarded header is syntactially valid,append to it
        "~^(,[ \\t]*)*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*([ \\t]*,([ \\t]*([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?(;([!#$%&'*+.^_`|~0-9A-Za-z-]+=([!#$%&'*+.^_`|~0-9A-Za-z-]+|\"([\\t \\x21\\x23-\\x5B\\x5D-\\x7E\\x80-\\xFF]|\\\\[\\t \\x21-\\x7E\\x80-\\xFF])*\"))?)*)?)*$" "$http_forwarded,$proxy_forwarded_elem";

        # Otherwise,replace it
        default "$proxy_forwarded_elem";

    }

    # Load configs
    include /etc/Nginx/conf.d/localhost.conf;
}

和 localhost.conf

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name localhost;
    root /usr/share/Nginx/html;

    ssl_certificate         /etc/Nginx/live/localhost/cert.pem;
    ssl_certificate_key     /etc/Nginx/live/localhost/key.pem;

    include /etc/Nginx/conf.d/security.conf;

    include /etc/Nginx/conf.d/proxy.conf;

    access_log /var/log/Nginx/access.log;
    error_log /var/log/Nginx/error.log info;

    # Nginx render files or proxy the request
    location / {
        try_files $uri @front;
    }

    location @front {
        proxy_pass http://frontend:80;
    }

    location ^~ /api/v1 {
        proxy_read_timeout 30m; # because an inference with SIMP can takes some time
        proxy_send_timeout 30m;
        proxy_connect_timeout 30m;
        proxy_pass http://backend:4000;
    }

    location = /report.html {
        root /usr/share/goaccess/html/;
    }

    location ^~ /ws {
        proxy_pass http://goaccess:7890;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_read_timeout 7d;
        proxy_connect_timeout 3600;
    }

    include /etc/Nginx/conf.d/general.conf;
}

编辑: 请求是通过 Angular HttpClient 发送的,也许此模块的构建方式是在短时间内未发送响应时中止请求,我将尝试对此进行调查。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)