我是靠谱客的博主 深情大白,最近开发中收集的这篇文章主要介绍Nginx请求体过大报错413,request_body日志频频为空,实战排查全过程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

承接之前文章使用openresty来搭建https代理与日志打印,随着时间的流逝,我搭建的openresty已经上了公司的生产服务器,就在这周五出现了一个新问题,于是我开始了探索了历程!那么问题是什么呢?又是怎么解决的呢?下面我们带着疑问往下看!
在这里插入图片描述

出现这个问题之后,公司同事找到我,说道:“我在网上查了加了client_max_body_size参数为20m的大小怎么日志打印的request_body为空呢?”。然后我当时脑子是懵的,于是将他修改的配置还原到原来的样子,看到了如下这大大的报错信息,我想:这报错信息很明显啦。信心满满的我找他要到了请求的报文和接口地址,发现请求报文大到原生记事本打开直接崩掉,最终我还是开始问题的排查!

openresty请求体过大导致413报错
在这里插入图片描述

首先,我认为既然用nginx代理转发接口地址,nginx所在服务器IP和域名与转发地址一定是网络互通的,你可以使用ping或者telnet的方式来检查。我认为这是有必要的,因为你所排查的问题都得建立在网络互通前提下,要不然排查途中发现很浪费你的时间和耐心,同样也会影响你的排查思路和心情!所以检查完以后我的网络是互通的,那么继续排查!

其次,nginx是一个轻量级服务,请求的过大的话需要更改请求体大小限制的,而且你的请求是从浏览器发出的,浏览器是有一个请求头的Content-Length默认为1m的大小,所以我们必须先更改nginx接受请求大小的限制来解决413报错问题。

client_max_body_size 50m;

当配置完以后发现413报错没有了,当我发起一个请求后,发现postman控制台为500报错,这就证明了请求体确实为空,因为你该传的请求体没有传导致后端报500错误。而且我在日志打印的时候看不到request_body的内容,简单来说也就是request_body为空,那么为什么呢?我已经配置解决request_body为空的配置项了呀,那怎么还是为空呢?

然后我想到了client_body_buffer_size来将请求缓存起来。Nginx分配给请求体的Buffer大小,如果请求的数据小于client_body_buffer_size就直接将数据先在内存中存储。如果请求的值大于client_body_buffer_size小于client_max_body_size,就会将数据先存储到临时文件中,在哪个临时文件中呢?答案是在nginx/client_body_temp。所以我们也要保证client_body_temp有读写权限,否则,当传输的数据大于client_body_buffer_size,写进临时文件失败会报错。你可以在error.log中查看到写进临时文件的日志。经过我的排查结果是我真的没有读写权限,甚至连看文件夹的权限都没有!

在我找公司系统管理员开权限之前总结一下:传输的数据大于client_max_body_size,一定是传不成功的。小于client_body_buffer_size直接在内存中高效存储。如果大于client_body_buffer_size小于client_max_body_size会存储临时文件,临时文件一定要有权限。如果追求效率,就设置 client_max_body_size client_body_buffer_size相同的值,这样就不会存储临时文件,直接存储在内存。

在这里插入图片描述

我顺着杆子爬,找到了管理员打开了client_body_temp的读写权限,结果发现并没有解决问题。其实我网上浏览其他人的解决办法的时候大概也就到这了,但是我还是没有解决。我就想:是不是我的配置没有加载到呢,因为之前也发生过这种现象,这一次我没有向往常一样reload。而是选择了另外一种方式杀光了nginx的所有进程,重新启动nginx。发现依赖不奏效,还是有问题,这时我逐渐失去了耐心!

在这里插入图片描述

突然大脑闪过了一种想法,是不是这个请求超时了呀,因为之前我配置里没有配置超时的配置项!于是,我配置了超时的配置项,reload重新加载配置文件,突然发现问题解决了!

proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_send_timeout 300;  
client_header_timeout 5m;
client_body_timeout 5m;

知识分享

问题得到了解决,其中在这个过程中还发现到了一些知识点,就是nginx转发当中使用http1.0和http1.1版本的问题。因为开始我怀疑过keep-alive的问题,很显然不是这个问题!

nginx在反向代理http协议时,默认使用的http1.0。而http1.0和http1.1的区别就是http1.0不支持http keep-alive。有需要的小伙伴也可以在我下面给出的配置文件中找到并配置!

HTTP类型描述
http1.0不支持keep-aliveConnection Close通知后端服务器主动关闭连接。导致任何一个客户端的请求都在后端服务器上产生了一个TIME-WAIT状态的连接
http1.1支持keep-aliveNginx上启用HTTP1.1的向后端发送请求,同时支持Keep-alive
#user  nobody; # 用户组
worker_processes  1;

# 打开错误日志和pid注释
error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    
    # 配置打印日志的格式,为了更好的排查问题打印的日志内容做了精简,这里我只留下了排查问题必不可少的日志内容
    log_format main  escape=json '{ "@timestamp": "$time_local", '
                         '"upstream_addr": "$upstream_addr",'
                         '"request_time": "$request_time", '
                         '"status": "$status", '
                         '"request": "$request", '
                         '"host":""$host",'
                         '"http_uri": "$uri",'
                         '"请求报文":"$request_body",'
                         '"响应报文":"$resp_body" }'

    # 开启日志缓存以免过多的使用内存
    open_log_file_cache max=1000 inactive=20s valid=1m min_use=2;
    sendfile        on;
    keepalive_timeout  65;
   
    # 以下解决了请求体过大问题
    client_max_body_size 50m;
   
    # 以下解决request_body为空问题 
    # 指定本地需要用多少和多大的缓冲区来缓冲FastCGI的应答
    fastcgi_buffers 32 16k;
    # 缓冲区代理缓冲用户端请求的最大字节数
    client_body_buffer_size 1024k;

    # HTTPS server
    #
    server {
        listen       443 ssl; # https默认端口
        server_name  xxx.com; # 域名
		
		# 以下配置为证书配置
        ssl_certificate      /data/openresty-1.15/nginx/conf/server.pem;
        ssl_certificate_key  /data/openresty-1.15/nginx/conf/server.key;

    	# 以下为证书套件等配置
        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on;
        
        # 添加以下配置
        charset utf-8;
        set $resp_body "";
        access_log  /data/openresty-1.15/nginx/logs/nginx.log  main; # 配置日志路径

        location / {
            #root   html;
            #index  index.html index.htm;
            
            # 开启强制获取请求报文日志
            lua_need_request_body on;
            log_escape_non_ascii off;
            # lua
            body_filter_by_lua '
                local resp_body = string.sub(ngx.arg[1], 1, 1000)
                ngx.ctx.buffered = (ngx.ctx.buffered or "") .. resp_body
                if ngx.arg[2] then
                    ngx.var.resp_body = ngx.ctx.buffered
                end
            ';
            
            # 以下配置均为请求超时配置
            proxy_connect_timeout 300;
            proxy_read_timeout 300;
            proxy_send_timeout 300;
        	client_header_timeout 5m;
        	client_body_timeout 5m;       
            
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            
            # 指定http1.1版本
            # proxy_http_version 1.1;
            # 设置Connection为空串,以禁止传递头部到后端
            # proxy_set_header Connection "";
			# proxy_set_header X-Forwarded-Proto $scheme;
            # proxy_set_header X-Forwarded-For $remote_addr;
            # 指定转发请求头携带host
            # proxy_set_header Host $http_host;
            # proxy_set_header X-Real-IP $remote_addr;

            proxy_pass https://IP:端口/index.jsp; # 代理转发的地址或域名
        }
    }
}

最后

以上就是深情大白为你收集整理的Nginx请求体过大报错413,request_body日志频频为空,实战排查全过程的全部内容,希望文章能够帮你解决Nginx请求体过大报错413,request_body日志频频为空,实战排查全过程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部