第5章 - 网络问题排查
嗨,所有开发者们!
在实际工作中,你一定遇到过各种网络问题:接口调不通、网站打不开、请求超时、跨域报错……这些问题看起来很神秘,但只要掌握正确的排查方法,就能快速定位问题。
这一章,我会总结最常见的网络问题和解决方法,让你成为网络问题排查高手!
🔍 网络不通问题
问题现象
- ping 不通服务器
- 浏览器无法打开网站
- 接口请求失败
- SSH 连不上服务器
排查步骤
# 步骤1: 检查本地网络
ping 127.0.0.1
# 如果失败,说明本机网络协议栈有问题
# 步骤2: 检查网卡状态
ip link show
ifconfig
# 查看网卡是否 UP
# 如果是 DOWN,执行: sudo ip link set eth0 up
# 步骤3: 检查IP配置
ip addr show
# 确认是否获取到IP地址
# 如果没有,检查DHCP或静态IP配置
# 步骤4: 检查网关
ip route show
route -n
# 确认是否有默认网关
# 如果没有,添加: sudo ip route add default via 192.168.1.1
# 步骤5: 测试网关连通性
ping $(ip route | grep default | awk '{print $3}')
# 如果失败,检查物理连接或网关配置
# 步骤6: 测试公网连通性
ping 8.8.8.8
# 如果失败,可能是网关、防火墙或ISP问题
# 步骤7: 测试DNS解析
ping baidu.com
nslookup baidu.com
# 如果IP可以ping通但域名不行,是DNS问题
# 步骤8: 追踪路由
traceroute 8.8.8.8
tracepath baidu.com
# 查看在哪个路由节点丢包
# 步骤9: 检查防火墙
sudo iptables -L -n -v
sudo ufw status
# 查看是否被防火墙阻挡
# 步骤10: 检查端口状态
sudo netstat -tunlp | grep :80
sudo ss -tunlp | grep :80
# 确认服务是否在监听
常见原因和解决方案
| 原因 | 现象 | 解决方案 |
|---|---|---|
| 网线未连接 | 网卡状态DOWN | 检查物理连接,重启网卡 |
| IP配置错误 | 没有IP地址 | 重新配置IP或DHCP |
| 网关配置错误 | 无法访问外网 | 正确配置默认网关 |
| DNS问题 | 域名无法解析 | 修改DNS服务器 |
| 防火墙阻挡 | 特定端口不通 | 调整防火墙规则 |
| 路由问题 | 部分网站不可访问 | 检查路由表,联系网络管理员 |
🔍 DNS 解析问题
问题现象
- 域名无法解析
- 解析速度慢
- 解析到错误的IP
排查步骤
# 1. 检查DNS配置
cat /etc/resolv.conf
# 确认nameserver配置是否正确
# 2. 测试DNS解析
nslookup baidu.com
dig baidu.com
host baidu.com
# 3. 指定DNS服务器测试
nslookup baidu.com 8.8.8.8
dig @8.8.8.8 baidu.com
# 对比不同DNS服务器的解析结果
# 4. 查看DNS缓存
sudo systemd-resolve --statistics
# Ubuntu/Debian
# 5. 清除DNS缓存
sudo systemd-resolve --flush-caches # Ubuntu/Debian
sudo killall -HUP mDNSResponder # macOS
ipconfig /flushdns # Windows
# 6. 检查hosts文件
cat /etc/hosts
# 查看是否有错误的静态解析
# 7. 测试DNS服务器连通性
ping 8.8.8.8
telnet 8.8.8.8 53
nc -zv 8.8.8.8 53
常用DNS服务器
# 国内DNS
114.114.114.114 # 114 DNS
223.5.5.5 # 阿里 DNS
119.29.29.29 # DNSPod
# 国外DNS
8.8.8.8 # Google DNS
8.8.4.4 # Google DNS
1.1.1.1 # Cloudflare DNS
1.0.0.1 # Cloudflare DNS
解决方案
# 1. 修改DNS服务器
sudo nano /etc/resolv.conf
# 添加:
nameserver 8.8.8.8
nameserver 114.114.114.114
# 2. Ubuntu/Debian 永久修改
sudo nano /etc/systemd/resolved.conf
# 修改:
DNS=8.8.8.8 114.114.114.114
sudo systemctl restart systemd-resolved
# 3. CentOS/RHEL
sudo nano /etc/sysconfig/network-scripts/ifcfg-eth0
# 添加:
DNS1=8.8.8.8
DNS2=114.114.114.114
sudo systemctl restart network
⏱️ 接口超时问题
问题现象
- 请求超时
- 响应很慢
- 间歇性超时
排查步骤
# 1. 测试网络延迟
ping api.example.com
# 查看平均延迟时间
# 2. 测试连接时间
time curl -I https://api.example.com
# 查看总耗时
# 3. 详细请求耗时分析
curl -w "@curl-format.txt" -o /dev/null -s https://api.example.com
# curl-format.txt 内容:
time_namelookup: %{time_namelookup}s\n
time_connect: %{time_connect}s\n
time_appconnect: %{time_appconnect}s\n
time_pretransfer: %{time_pretransfer}s\n
time_redirect: %{time_redirect}s\n
time_starttransfer: %{time_starttransfer}s\n
time_total: %{time_total}s\n
# 4. 检查服务器负载
top
htop
uptime # 查看负载均值
# 5. 检查数据库连接
# MySQL
SHOW PROCESSLIST;
SHOW STATUS LIKE 'Threads%';
# 6. 检查日志
tail -f /var/log/nginx/error.log
tail -f /var/log/application.log
常见原因
// 1. 网络延迟高
// 解决:
// - 使用CDN加速
// - 选择距离更近的服务器
// - 优化网络路由
// 2. 服务器处理慢
// 解决:
// - 优化代码逻辑
// - 添加缓存
// - 增加服务器资源
// 3. 数据库查询慢
// 解决:
// - 添加索引
// - 优化SQL语句
// - 使用查询缓存
// 4. 连接池耗尽
// 解决:
// - 增大连接池
// - 修复连接泄漏
// - 设置连接超时
// 5. 第三方服务慢
// 解决:
// - 设置超时时间
// - 使用异步请求
// - 添加重试机制
优化建议
// 设置合理的超时时间
const axios = require('axios');
const api = axios.create({
timeout: 5000, // 5秒超时
retry: 3, // 重试3次
retryDelay: 1000 // 重试间隔1秒
});
// 添加超时重试
api.interceptors.response.use(null, async (error) => {
const config = error.config;
if (!config || !config.retry) {
return Promise.reject(error);
}
config.__retryCount = config.__retryCount || 0;
if (config.__retryCount >= config.retry) {
return Promise.reject(error);
}
config.__retryCount += 1;
await new Promise(resolve => setTimeout(resolve, config.retryDelay));
return api(config);
});
❌ 跨域问题 (CORS)
问题现象
// 控制台错误:
Access to XMLHttpRequest at 'https://api.example.com/users'
from origin 'https://www.example.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
排查步骤
# 1. 检查是否跨域
# 当前页面: https://www.example.com
# 请求接口: https://api.example.com
# 协议/域名/端口不同即为跨域
# 2. 检查响应头
curl -I https://api.example.com/users
# 查看是否有 Access-Control-Allow-Origin 头
# 3. 测试 OPTIONS 请求
curl -X OPTIONS https://api.example.com/users \
-H "Origin: https://www.example.com" \
-H "Access-Control-Request-Method: POST" \
-v
# 查看预检请求是否成功
后端解决方案
// Express.js
const cors = require('cors');
// 方法1: 允许所有源 (仅开发环境)
app.use(cors());
// 方法2: 指定允许的源 (推荐)
app.use(cors({
origin: ['https://www.example.com', 'https://app.example.com'],
credentials: true, // 允许携带Cookie
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: 86400 // 预检结果缓存24小时
}));
// 方法3: 手动设置响应头
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,Authorization');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
# Nginx 配置
server {
listen 80;
server_name api.example.com;
location / {
# 允许所有源 (仅开发环境)
add_header Access-Control-Allow-Origin *;
# 指定允许的源 (推荐)
add_header Access-Control-Allow-Origin "https://www.example.com";
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Access-Control-Max-Age 86400;
# 处理 OPTIONS 请求
if ($request_method = OPTIONS) {
return 204;
}
proxy_pass http://localhost:3000;
}
}
前端解决方案
// 方法1: 使用代理 (开发环境)
// vite.config.js
export default {
server: {
proxy: {
'/api': {
target: 'https://api.example.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
}
// 使用
fetch('/api/users') // 实际请求 https://api.example.com/users
// 方法2: JSONP (仅支持GET)
function jsonp(url, callback) {
const callbackName = 'jsonp_' + Date.now();
window[callbackName] = callback;
const script = document.createElement('script');
script.src = `${url}?callback=${callbackName}`;
document.body.appendChild(script);
}
🔒 HTTPS 证书问题
问题现象
- 浏览器提示“您的连接不是私密连接”
- SSL 证书过期
- 证书域名不匹配
- 中间证书缺失
排查步骤
# 1. 检查证书信息
openssl s_client -connect example.com:443 -servername example.com
# 查看证书详情
# 2. 检查证书有效期
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -dates
# 3. 检查证书链
openssl s_client -connect example.com:443 -showcerts
# 4. 验证证书
openssl verify -CAfile ca-bundle.crt certificate.crt
# 5. 在线检测工具
# https://www.ssllabs.com/ssltest/
解决方案
# 1. 使用 Let's Encrypt 免费证书
# 安装 certbot
sudo apt install certbot python3-certbot-nginx
# 申请证书
sudo certbot --nginx -d example.com -d www.example.com
# 自动续期
sudo certbot renew --dry-run
# 添加到 crontab
0 3 * * * certbot renew --quiet
# 2. 配置 Nginx HTTPS
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
}
# 3. HTTP 自动跳转 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
🐌 网络慢的原因分析
问题现象
- 网页加载慢
- 接口请求慢
- 文件下载慢
排查步骤
# 1. 测试网络速度
# 下载 speedtest-cli
sudo apt install speedtest-cli
speedtest-cli
# 2. 测试带宽
wget http://speedtest.tele2.net/100MB.zip
# 查看下载速度
# 3. 检查网络延迟
ping -c 100 api.example.com
# 查看平均延迟和丢包率
# 4. 检查MTU设置
ip link show
# MTU 通常为 1500
# 5. 检查网络负载
iftop -i eth0
nload eth0
# 6. 检查连接数
netstat -an | grep ESTABLISHED | wc -l
ss -s
# 7. 检查服务器负载
top
htop
uptime
常见原因
// 1. 网络带宽不足
// 解决:
// - 升级带宽
// - 使用CDN
// - 压缩资源
// 2. DNS解析慢
// 解决:
// - 更换DNS服务器
// - 使用DNS缓存
// 3. 资源文件过大
// 解决:
// - 压缩图片
// - 使用WebP格式
// - 代码分割加载
// 4. 请求数量过多
// 解决:
// - 合并请求
// - 使用精灵图
// - 懒加载
// 5. 服务器处理慢
// 解决:
// - 优化代码
// - 添加缓存
// - 水平扩展
// 6. 数据库查询慢
// 解决:
// - 添加索引
// - 优化SQL
// - 使用读写分离
🛠️ 常用诊断命令
网络连通性
# ping - 测试网络连通性
ping -c 4 baidu.com
# traceroute - 追踪路由
traceroute baidu.com
tracepath baidu.com
# mtr - 综合ping和traceroute
mtr baidu.com
# telnet - 测试端口连通性
telnet 192.168.1.100 80
# nc (netcat) - 网络工具
nc -zv 192.168.1.100 80
nc -l 8888 # 监听端口
DNS诊断
# nslookup - DNS查询
nslookup baidu.com
nslookup baidu.com 8.8.8.8
# dig - DNS详细信息
dig baidu.com
dig @8.8.8.8 baidu.com
dig +trace baidu.com # 跟踪DNS解析过程
# host - 简单DNS查询
host baidu.com
网络状态
# netstat - 网络连接状态
netstat -tunlp # 查看所有监听端口
netstat -an | grep EST # 查看已建立连接
netstat -s # 网络统计信息
# ss - 更快的netstat
ss -tunlp
ss -s # 统计信息
# lsof - 查看端口占用
sudo lsof -i :80
sudo lsof -i tcp
抓包分析
# tcpdump - 抓包工具
sudo tcpdump -i eth0
sudo tcpdump -i eth0 port 80
sudo tcpdump -i eth0 host 192.168.1.100
sudo tcpdump -i eth0 -w capture.pcap
# tshark - Wireshark命令行版
tshark -i eth0
tshark -r capture.pcap
HTTP请求
# curl - HTTP客户端
curl -I https://baidu.com # 查看响应头
curl -v https://baidu.com # 详细信息
curl -X POST -d '{"key":"value"}' https://api.example.com
# wget - 下载工具
wget https://example.com/file.zip
wget -O output.html https://example.com
# ab - 性能测试
ab -n 1000 -c 10 https://example.com/
📝 快速排查流程图
graph TB
A[网络问题] --> B{能启ping通吗?}
B -->|No| C[检查网络配置]
C --> C1[检查网卡状态]
C --> C2[检查IP配置]
C --> C3[检查网关配置]
B -->|Yes| D{IP可以但域名不可以?}
D -->|Yes| E[DNS问题]
E --> E1[检查DNS配置]
E --> E2[清除DNS缓存]
E --> E3[更换DNS服务器]
D -->|No| F{特定端口不通?}
F -->|Yes| G[防火墙问题]
G --> G1[检查防火墙规则]
G --> G2[检查服务状态]
F -->|No| H{请求超时?}
H -->|Yes| I[性能问题]
I --> I1[检查服务器负载]
I --> I2[检查数据库性能]
I --> I3[优化代码]
H -->|No| J[其他问题]
J --> J1[查看错误日志]
J --> J2[抓包分析]
💡 最佳实践
1. 日常检查清单
#!/bin/bash
# daily-check.sh - 每日网络检查
echo "=== 日常网络检查 ==="
echo "时间: $(date)"
echo ""
# 1. 网络连通性
echo "1. 网络连通性"
ping -c 4 8.8.8.8 > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo " ✅ 网络连通性正常"
else
echo " ❌ 网络连接失败"
fi
# 2. DNS解析
echo "2. DNS解析"
nslookup baidu.com > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo " ✅ DNS解析正常"
else
echo " ❌ DNS解析失败"
fi
# 3. 关键服务
echo "3. 关键服务"
for service in nginx mysql; do
systemctl is-active --quiet $service
if [ $? -eq 0 ]; then
echo " ✅ $service 运行正常"
else
echo " ❌ $service 未运行"
fi
done
# 4. 端口监听
echo "4. 端口监听"
for port in 80 443 3306; do
netstat -tunl | grep ":$port" > /dev/null
if [ $? -eq 0 ]; then
echo " ✅ 端口 $port 正在监听"
else
echo " ❌ 端口 $port 未监听"
fi
done
# 5. SSL证书
echo "5. SSL证书检查"
CERT_FILE="/etc/letsencrypt/live/example.com/cert.pem"
if [ -f "$CERT_FILE" ]; then
EXPIRY=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt 30 ]; then
echo " ⚠️ 证书将在 $DAYS_LEFT 天后过期"
else
echo " ✅ 证书有效期还有 $DAYS_LEFT 天"
fi
fi
echo ""
echo "=== 检查完成 ==="
2. 问题记录
# 网络问题记录表
| 日期 | 问题描述 | 原因 | 解决方案 | 处理人 |
|------|----------|------|----------|--------|
| 2024-01-15 | 接口超时 | 数据库查询慢 | 添加索引 | 张三 |
| 2024-01-10 | 跨域错误 | 未CORS配置 | 后端添加CORS | 李四 |
| 2024-01-05 | DNS解析失败 | DNS服务器故障 | 更换DNS | 王五 |
3. 建立监控告警
// monitor.js - 简单的接口监控
const axios = require('axios');
const endpoints = [
{ name: '主页', url: 'https://example.com' },
{ name: '用户API', url: 'https://api.example.com/users' },
{ name: '订单API', url: 'https://api.example.com/orders' }
];
async function checkEndpoint(endpoint) {
try {
const startTime = Date.now();
const response = await axios.get(endpoint.url, { timeout: 5000 });
const duration = Date.now() - startTime;
console.log(`✅ ${endpoint.name}: ${response.status} (${duration}ms)`);
if (duration > 1000) {
console.warn(`⚠️ ${endpoint.name} 响应较慢: ${duration}ms`);
}
} catch (error) {
console.error(`❌ ${endpoint.name}: ${error.message}`);
// 发送告警通知
}
}
async function monitor() {
console.log(`[${new Date().toISOString()}] 开始监控...`);
for (const endpoint of endpoints) {
await checkEndpoint(endpoint);
}
console.log('');
}
// 每分钟检查一次
setInterval(monitor, 60000);
monitor();
📝 小结
这一章我们学习了:
✅ 网络不通排查:系统性排查网络连接问题
✅ DNS问题:DNS解析失败、解析慢的解决
✅ 接口超时:定位和优化超时问题
✅ 跨域问题:CORS配置和解决方案
✅ HTTPS证书:证书问题排查和配置
✅ 性能问题:网络慢的原因分析和优化
✅ 诊断工具:掌握常用网络诊断命令
🎉 恐喜你!
恐喜你完成了所有实战案例的学习!
现在你已经:
✅ 掌握了计算机网络的基础知识
✅ 理解了网络协议的工作原理
✅ 学会了在实际工作中应用网络知识
✅ 掌握了网络问题的排查方法
接下来建议你:
- 持续实践 - 在工作中应用所学知识
- 总结经验 - 记录遇到的问题和解决方法
- 深入学习 - 阅读相关技术书籍和文档
- 分享交流 - 和同事分享你的经验
- 关注动态 - 关注网络技术的最新发展
由 编程指南 提供
