当客户端取消连接时,Nginx(作为 revser 代理)不会通知 gin-gonic(作为 Web 服务器)

Bon*_*Fir 7 nginx go go-gin nginx-reverse-proxy

gin-gonic用作网络服务器和nginx代理服务器的网站中,客户端通过gin-conic公开的 API将他们的数据发送到服务器,并且为了向客户端发送服务器命令,每个(即客户端)都与网络服务器建立连接,并保留它很长一段时间(即几个小时内不会过期)并用所需的命令填充他们的响应主体(对于双向连接,我们可以使用它ws来代替)。

问题是我们需要了解客户端是否删除/取消了与服务器的连接。为了理解我们case <-c.Request.Context().Done():在下面的代码中有这一行。

func MakeConnection(c *gin.Context) {
// ... code
select {
case notification = <-clientModel.Channels[token]:// we have a command to send to user
    log.Info("Notification")
    err = nil
case <-c.Request.Context().Done(): // connection dropped by client
    log.Info("Cancel")
    err = c.Err()
case <-ctx.Done(): // time elapsed and there was no command to send to client
    log.Info("timeout")
    err = errors.New("timeout exceeded")
}
// ... code
}
Run Code Online (Sandbox Code Playgroud)

一切正常(如果我们与服务器建立这样的连接并在任意时间后取消它,立即Cancel显示在终端中),直到客户端数量增加。

对于大约 5 个客户端,这项工作按预期进行,但对于 10 个以上的客户端(更多负载),尽管ngixn在其访问日志中记录取消(作为错误代码499),但网络服务器(即gin-gonic)没有得到通知。

nginx 配置

server {
    # SSL configuration
    listen 443 ssl http2 so_keepalive=10:150:1;
    listen [::]:443 ssl http2 so_keepalive=10:150:1;
    include /etc/nginx/snippets/self-signed.conf;
    include /etc/nginx/snippets/ssl-params.conf;

    root /var/www/project;
    autoindex off;

    location / {
        try_files $uri $uri/ @proxy;
    }

    location ~ /v1/v/[0-9a-zA-Z]+/notification {
        proxy_connect_timeout       86460;
        proxy_send_timeout          86460;
        proxy_read_timeout          86460;
        send_timeout                86460;
        proxy_pass                  http://example_host:8002;
    }
}

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
    use epoll;
    multi_accept on;
}

http {
    limit_req_zone $binary_remote_addr zone=req_zone:200m rate=10r/s;
    limit_req_zone $request_uri zone=search_limit:100m rate=5r/s;
    limit_req_zone $binary_remote_addr zone=login_limit:100m rate=20r/m;
    vhost_traffic_status_zone;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$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  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    gzip  on;
    gzip_types  text/html text/css text/javascript text/xml text/plain
                image/x-icon image/svg+xml 
                application/rss+xml application/javascript application/x-javascript 
                application/xml application/xhtml+xml 
                application/x-font application/x-font-truetype application/x-font-ttf application/x-font-otf application/x-font-opentype application/vnd.ms-fontobject font/ttf font/otf font/opentype
                font/woff font/ttf
                application/octet-stream;
    gzip_vary on;

    include /etc/nginx/conf.d/*.conf;
}
Run Code Online (Sandbox Code Playgroud)