离奇的 Connection reset by peer 和 Broken pipe 报错解决方案
近期上线了一个 Spring Boot 前后端不分离的一体式项目。在本地测试的时候,项目正常运行,没有任何报错,部署到服务器上时,出现了这样离奇的问题:
- 使用 ip:port 访问项目时,可以正常访问,日志内没有任何报错。
- Nginx 配置反向代理,通过域名访问项目时,可以正常访问,但是日志内出现了报错。
报错信息如下:
2021-06-02 15:39:15.316 ERROR 19196 --- [io-7797-exec-91] c.x.j.a.c.resolver.WebExceptionResolver : WebExceptionResolver:{}
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Connection reset by peer
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:351) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41]
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:776) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41]2021-06-02 15:39:15.318 ERROR 19196 --- [io-7797-exec-95] c.x.j.a.c.resolver.WebExceptionResolver : WebExceptionResolver:{}
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:351) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41]
at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:776) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41]虽然在 Nginx 反向代理的场景下日志文件有报错信息,但是项目又可以正常运行。但是长此以往日志文件就会越积越多,能解决一个报错是一个报错。
经过两天的百度搜索,能得到一些统一的答案:网络异常、提前关闭,很多博客说得云里雾里的。大部分博客对于这个问题的解决方案,要么都是复制粘贴,重复内容一大堆,要么就是一点实质性的东西都没有,终究还是得自己摸索。
先总结一下百度找到的几个原因和解决方案:
- Connection reset by peer 全解:https://www.cnblogs.com/crazymakercircle/p/14001467.html
- Broken pipe 错误终极解释:https://www.cnblogs.com/metoy/p/6565486.html
林子大了什么鸟都有,代码写多了什么 BUG 都有。
出现这个问题之后,我仔细分析了一下,可能是 Nginx 反向代理配置的问题。参考搜索结果,修改 Nginx 缓存等等等乱七八糟的反向代理配置,毫无作用。
想到异常信息中出现了 java.io.IOException 这个字眼,我想会不会是因为某个文件请求出问题了。因此我在程序中加了个自定义异常处理的操作,捕获一下这个异常产生时所请求的 URL 和请求参数相关信息。
自定义异常处理做好之后,我又在反向代理的环境下访问了一次项目。自定义异常输出的内容大概是:
请求链接:xxxxx/xxx.png(是个图片)
异常名称:org.apache.catalina.connector.ClientAbortException: java.io.IOException: Connection reset by peer由此可见:由于静态资源的的未知原因,在反向代理的环境下访问静态资源,会报出这个异常,但是静态资源能正常加载。
解决方法:Nginx 反向代理时,针对静态资源单独设置规则。
location ~ .*.(gif|jpg|png|html|htm|css|js|ico|swf|pdf|ttf|woff|woff2)$ {
proxy_redirect off;
proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
proxy_set_header Host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8081;
#Use Proxy Cache
#Set Nginx Cache
proxy_ignore_headers Set-Cookie Cache-Control expires;
add_header Cache-Control no-cache;
proxy_cache_valid any 2d;
}单独对静态资源下手后,问题解决,至此也没有再爆出这些错误。
至于问题出现的原因,有可能是因为 Nginx 反向代理缓存配置的原因,也有可能是其他未知原因。但是能确定的是,反向代理过程中某一端提前关闭请求,才会造成 java.io.IOException: Broken pipe。深层原因就有待深究了。
反正就是离谱。