Appearance
HTTP 常见问题排查
跨域问题
问题现象
- 浏览器控制台出现 CORS 错误
- OPTIONS 预请求失败
- 跨域携带 Cookie 失败
可能原因
- 服务器未设置 CORS 响应头
- 前端请求头配置不正确
- 跨域请求携带了 credentials
排查步骤
- 检查浏览器控制台错误信息
- 查看网络请求中的 OPTIONS 请求
- 检查服务器响应头
解决方案
- 服务器端:设置
Access-Control-Allow-Origin、Access-Control-Allow-Methods等响应头 - 前端:使用 Axios 时设置
withCredentials: true
代码示例
javascript
// 服务器端(Express)
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});
// 前端(Axios)
axios.defaults.withCredentials = true;请求异常
问题现象
- 请求发送失败
- 请求超时
- 重复请求
- 请求参数传递错误
可能原因
- 网络连接问题
- 服务器响应慢
- 前端代码逻辑问题
- 参数格式不正确
排查步骤
- 检查网络连接
- 查看浏览器网络面板
- 检查请求参数格式
- 检查服务器日志
解决方案
- 设置合理的超时时间
- 实现请求防抖/节流
- 检查参数格式和编码
- 优化服务器响应速度
代码示例
javascript
// 设置超时时间
axios.defaults.timeout = 10000;
// 防止重复请求
const pendingRequests = new Map();
axios.interceptors.request.use(config => {
const key = `${config.method}:${config.url}`;
if (pendingRequests.has(key)) {
return Promise.reject(new Error('重复请求'));
}
pendingRequests.set(key, true);
return config;
}, error => {
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
const key = `${response.config.method}:${response.config.url}`;
pendingRequests.delete(key);
return response;
}, error => {
const key = `${error.config.method}:${error.config.url}`;
pendingRequests.delete(key);
return Promise.reject(error);
});响应异常
问题现象
- 状态码 401(未授权)
- 状态码 403(禁止访问)
- 状态码 404(接口不存在)
- 状态码 500(服务器错误)
- 状态码 502(网关错误)
可能原因
- Token 过期或无效
- 用户权限不足
- 接口路径错误
- 服务器内部错误
- 网关配置错误
排查步骤
- 检查状态码和错误信息
- 验证 Token 是否有效
- 检查接口路径是否正确
- 查看服务器日志
解决方案
- 401:重新登录获取 Token
- 403:检查用户权限
- 404:修正接口路径
- 500/502:联系后端开发人员
代码示例
javascript
axios.interceptors.response.use(
response => response,
error => {
if (error.response) {
switch (error.response.status) {
case 401:
// Token 过期,跳转到登录页
window.location.href = '/login';
break;
case 403:
// 权限不足,显示提示
alert('您没有权限访问此资源');
break;
case 404:
// 接口不存在,显示提示
alert('请求的资源不存在');
break;
case 500:
case 502:
// 服务器错误,显示提示
alert('服务器内部错误,请稍后重试');
break;
}
}
return Promise.reject(error);
}
);缓存问题
问题现象
- 浏览器缓存导致接口数据不更新
- 缓存策略设置不当
- 缓存清除困难
可能原因
- 强缓存未过期
- 协商缓存验证失败
- 缓存策略配置错误
排查步骤
- 检查浏览器缓存设置
- 查看响应头中的缓存相关字段
- 检查服务器缓存配置
解决方案
- 设置合理的缓存策略
- 使用版本号或时间戳避免缓存
- 手动清除浏览器缓存
代码示例
javascript
// 避免缓存的请求
axios.get('/api/data', {
params: {
_t: Date.now() // 添加时间戳
}
});
// 设置缓存策略
axios.get('/api/data', {
headers: {
'Cache-Control': 'no-cache'
}
});安全问题
问题现象
- XSS 攻击
- CSRF 攻击
- 请求参数泄露
- HTTPS 配置问题
可能原因
- 输入验证不足
- 缺少 CSRF 令牌
- 明文传输敏感信息
- HTTPS 配置错误
排查步骤
- 检查输入验证
- 检查 CSRF 防护措施
- 检查请求是否使用 HTTPS
- 检查敏感信息传输
解决方案
- 实现输入验证和转义
- 使用 CSRF 令牌
- 加密敏感信息
- 强制使用 HTTPS
代码示例
javascript
// CSRF 防护
axios.defaults.xsrfCookieName = 'XSRF-TOKEN';
axios.defaults.xsrfHeaderName = 'X-XSRF-TOKEN';
// 加密敏感信息
import CryptoJS from 'crypto-js';
const encryptData = (data, key) => {
return CryptoJS.AES.encrypt(JSON.stringify(data), key).toString();
};
axios.post('/api/login', {
username: 'user',
password: encryptData('password', 'secretKey')
});