莫名奇妙的nginx请求偶发400

概览

背景

有部分数据状态变更时,需要通过回调地址通知客户内部系统更新数据状态。

网络链路如下所示:

云平台----->客户nginx前置机 (或其他防火墙)---->客户内网nginx ---->java应用

现象:

有些数据回调正常,有少量数据回调异常!客户本地数据无法更新状态,导致查询本地库数据状态错误。

拿具体的某个异常id查询相关日志发现以下现象

(1)云平台回调客户本地服务,云平台的回调服务日志中显示connection reset

(2)客户nginx的error日志显示 connect() failed (connection refused)

2024/10/12 16:59:29 [error] 87689#0: *197553200 connect() failed (111: Connection refused) while connecting to upstream, client: 47.94.142.197, server: localhost, request: "POST /gateway/call/signDataSynCall HTTP/1.1", upstream: "http://0.0.0.0:9999/回调接口url", host: "回调地址外网ip:端口"

(3)客户nginx打开了request_body开关,但异常回调的数据看不到accesslog的请求体,只能看到一个http请求 400的错误

分析过程

一 确认nginx配置

http 400的错误,搜网上大部分说请求参数的问题,比如请求体太大等,看nginx配置 最大500m没有超啊。

二 跳过nginx直接访问java应用接口

既然nginx到后台应用连接拒绝,直接通过内网curl -xpost方式是否能回调成功呢?

直接应用是成功的;说明java应用没问题。

三 内网nginx访问接口

直接内网访问nginx内网的ip+80端口也是通的。映射出的外网访问就不通,这很容易联想到是不是防火墙等其他拦截了?

问题到底出在哪儿里呢?最终还是找到我们运维老大帮忙,老大提供的建议是安全设备限制了…

看nginx配置 upstream除了正常的ip:端口外,还有个 0:端口 weight=1是什么鬼,大佬给去掉了,但问题依然存在。回调不通的订单还是回调不通,还是connection reset,但和之前不同的是:

nginx的error日志里连接拒绝的没有了,accesslog里的400也没有了,其实error里显示了连接拒绝的ip:端口 ,我还好奇0.0.0.0:9999怎么ip都是0,原来配置的upstream问题。

最终百思不得其解的我还是联系了客户的网络技术进行分析,触发接口调用,他进行抓包分析。

四 问题大揭秘

原来确实是被拦截了,客户使用了Discuz,这是一个门户的软件,有些版本有漏洞;回调的参数中字符串有的可能恰好和规则库里面Discuz!漏洞的字段吻合了导致被拦截

客户添加来源ip白名单,对于白名单里的回调内容,排除拦截放行!

### Nginx 返回 400 错误求的原因及解决方案 Nginx 返回 HTTP 400 错误通常表示客户端送的求存在语法错误或不符合服务器的要求。这种错误可能由多种原因引起,以下是一些常见原因及其对应的解决方案: #### 1. 求路径中包含无效字符 Nginx求路径中的字符有严格的限制。如果路径中包含不被允许的字符(如控制字符、空格等),Nginx 会返回 400 错误。 - **解决方法**:确保客户端送的求路径符合 URI 标准[^1]。可以通过对特殊字符进行 URL 编码来避免此问题。 ```python import urllib.parse path = "/example path with spaces" encoded_path = urllib.parse.quote(path) print(encoded_path) # 输出: /example%20path%20with%20spaces ``` #### 2. 求路径过长 某些情况下,Nginx 配置的 `large_client_header_buffers` 参数可能不足以处理过长的求路径,导致返回 400 错误。 - **解决方法**:调整 Nginx 配置文件中的 `large_client_header_buffers` 参数以支持更大的求头大小[^2]。 ```nginx http { large_client_header_buffers 4 16k; } ``` #### 3. 合并斜杠的配置问题 Nginx 的 `merge_slashes` 配置选项默认为开启状态,这意味着连续的斜杠会被合并为单个斜杠。如果关闭此选项,并且客户端送的求包含多个连续斜杠,则可能导致 400 错误。 - **解决方法**:检查 `merge_slashes` 配置是否适合当前的应用场景。如果需要保留多个连续斜杠,可以将其设置为 `off`,但需注意潜在的安全风险。 ```nginx http { merge_slashes off; } ``` #### 4. 求头过大 Nginx 默认对求头的大小有限制。如果客户端送的求头超过此限制,Nginx 会返回 400 错误。 - **解决方法**:通过调整 `client_header_buffer_size` 和 `large_client_header_buffers` 参数来增加求头的最大允许大小[^2]。 ```nginx http { client_header_buffer_size 64k; large_client_header_buffers 4 64k; } ``` #### 5. Memcached 求类型参数化问题 在使用 Nginx 与 Memcached 集成时,如果求类型需要通过查询字符串参数化,可能会因为内容类型检测机制导致 400 错误。 - **解决方法**:为自定义求类型实现特定的处理逻辑,确保 Nginx 能正确解析求[^2]。 ```nginx location /memcached { set $memcached_key $arg_key; memcached_pass 127.0.0.1:11211; default_type text/plain; } ``` ### 总结 Nginx 返回 400 错误的原因多样,包括求路径中的无效字符、路径过长、合并斜杠的配置问题、求头过大以及内容类型检测机制等。针对不同原因,可以采取相应的配置调整或代码优化措施来解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值