概述
承接之前文章使用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-alive | Connection Close通知后端服务器主动关闭连接。导致任何一个客户端的请求都在后端服务器上产生了一个TIME-WAIT状态的连接 |
http1.1 | 支持keep-alive | Nginx上启用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日志频频为空,实战排查全过程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复