最近发现nginx生产环境有499的日志,其片段如下:

HTTP/1.1" 499 0

google到可能是这个原因:

HTTP 499 在nginx中意为在服务器响应请求前客户端关闭了连接。

下面我们就来做个实验,验证一下是不是这个原因。实验的原理图如下:

浏览器请求nginx,然后nginx将请求转发到upstream服务器(Web Server),然后Web Server处理请求,还没写回响应的时候,用户主动关闭浏览器,Nginx会在日志中记录499的状态。

下面我们来做个实验,验证一下这个解释。主要分三个步骤:
  1. 创建upstream应用服务器
  2. 部署nginx反向代理服务器
  3. 在浏览器发起请求,然后关闭请求的网页。
1.创建upstream应用服务器

这里我用asp.net core mvc写一个简单的接口,其接受一个参数,可以hold住http请求,等待指定的时间(秒)后返回响应。代码如下:

public string Sleep(int seconds)
{
    var startTime = DateTime.Now.ToString("HH:mm:ss.fff");
    Thread.Sleep(seconds*1000);
    var endTime = DateTime.Now.ToString("HH:mm:ss.fff");
    return $"StartTime:{startTime}\r\nEndTime:{endTime}";
}

然后将应用创建为镜像,启动一个容器。Dockerfile如下:

FROM microsoft/dotnet:2.1-aspnetcore-runtime AS runtime
WORKDIR /app
COPY publish ./
ENTRYPOINT ["dotnet", "WebSleepApiTest.dll"]

然后运行容器:

[root@14-28 nginx]# docker run -d --name websleepapi -p 8801:80 websleepapi
然后在浏览器中验证下接口是否正常:

可以看到,请求按照我们输入的参数睡眠了8秒。

2.部署nginx服务器

这里也是用容器部署的nginx,下载官方镜像,然后写好自己的配置文件,创建并运行容器即可。nginx配置文件如下:

[root@14-28 nginx]# cat nginx.conf

user  nginx;
worker_processes  1;

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


events {
    worker_connections  1024;
}


http {
    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;
    upstream websleepapi{
        server 192.168.14.28:8801;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://websleepapi;
            proxy_http_version 1.1;
            proxy_connect_timeout 70s;
            proxy_read_timeout 70s;
            proxy_send_timeout 70s;
        }
    }


    include /etc/nginx/conf.d/*.conf;
}

其中upstream服务器就是我们第一步部署的应用服务器,这里配置nginx将请求转发到此服务器上。

然后创建并运行nginx容器:

[root@14-28 nginx]# docker run --name nginxtest -v /root/workspace/nginx/nginx.conf:/etc/nginx/nginx.conf:ro -p 9001:80 -d nginx:1.14

3.在浏览器中发起请求,验证499的场景

先在浏览器请求,指定参数80秒,这样应用服务器会睡眠80秒。

http://192.168.14.28:9001/home/sleep?seconds=80
这时候浏览器会处于等待响应的装填,请求被应用服务器hold住。
然后我们关闭这个页面,发现nginx打印了如下日志:
192.168.14.21 - - [24/Jul/2018:09:57:29 +0000] "GET /home/sleep?seconds=80 HTTP/1.1" 499 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" "-"
根据nginx默认的日志模板,上面这条日志中的499就是对应$status字段。
结论
此次实验证明如下结论是正确的:在服务器响应请求前客户端关闭了连接,nginx会将连接状态记录为499。

发表评论

电子邮件地址不会被公开。 必填项已用*标注