问题背景
这个报错发生在之前部署的一个前后端分离的项目中。后端使用的Spring Boot,前端使用的JavaScript,前后端交互使用Thymeleaf框架。
现象
现象大概是这样,项目组的小伙伴突然跟我说所有网页都打不开了,网页显示"目前无法处理此请求",如下图。
服务器上的日志是这样的:
这个异常是由一个Python定时脚本抛出的。这个脚本会定时请求服务的某个接口,请求中的url写的是公网IP。
问题排查
关于这个问题,我第一次处理,所以初步有几个猜想:
- 服务停止了
- 服务器网络断开了
服务是否停止?
在服务器上,查看java进程是否有在运行:
- 输入
jps
命令,显示有jar进程在运行 - 输入
ps -ef | grep <jar包名称> | grep -v grep
,显示有进程在运行
查看java服务端口是否正在监听:
- 输入
netstat -tuln | grep <服务端口>
,显示LISTEN
排查到这里,说明服务正常运行,端口也是在监听的,说明服务没有停止。
网络是否断开?
网络排查,首先就是ping:
- 在服务器上ping百度,能ping通
- 在本地ping服务器,能ping通
说明网络没问题。然后我尝试了telnet访问服务器的服务端口:
- 在服务器上用公网IP + 服务端口 telnet自己的服务端口,显示
telnet: Unable to connect to remote host: Connection refused
- 在本地用公网IP + 服务端口 telnet服务器的服务端口,显示
无法打开到主机的连接,连接失败
- 在服务器上用localhost + 服务端口 或者127.0.0.1 + 服务端口 telnet自己的服务端口,能够正常连接,显示
Connected to localhost.
到这里,发现只要用公网IP和端口,就访问不了。我又尝试了用curl
命令访问服务,发现也是这样,只要用公网IP就访问不了,不管是在本地还是在服务器上进行访问。我很好奇,这里localhost、127.0.0.1、公网IP明明都表示同一台机器,但是只有公网IP访问不了。
查资料才发现,如果用公网IP,数据包会离开本机 ,通过网络接口传输到互联网上(即到达路由器上),然后根据路由表和网络配置在网络上传输。而如果用localhost,数据包不会离开本机,只会在计算机内部循环。
所以到这里,猜测可能是路由器的服务器端口映射变了(关于端口映射,涉及到内网、外网的概念,可以参考:什么是端口映射?路由器如何设置端口映射?),导致ping虽然能ping通,但是telnet无法访问。
最后问了服务器那边的人员,发现是网站没有备案,导致被强制关闭了外网访问。
总结
网站无法打开,从以下几个方面排查问题:
- 网络是否正常
- 服务是否正常启动
- 路由器端口映射是否发生改变
- 是否由于没有备案,导致被强制关闭外网访问
也学习到了一些计算机网络的知识:
- ping localhost,数据包只在本机内部循环,不会到公网上
- ping本机的公网IP,数据包会离开本机,到达路由器上,然后再根据路由器配置发送到本机