本文目录导读:

针对“请求异常”的过滤拦截,通常需要根据你所处的技术栈(前端/后端)以及异常的类型(网络错误、业务错误、认证失败等)来设计,以下从前端和后端两个维度,以及客户端(Axios/Fetch) 和网关/中间件层面,给出具体的拦截方案。
前端层面(最常用)
前端拦截可以避免无效请求发出,或对异常进行统一处理(如弹窗、跳转登录)。
Axios 拦截器(推荐)
Axios 是最常用的 HTTP 客户端,其拦截器可以统一处理请求和响应异常。
// 创建 Axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000,
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 1. 过滤无效请求:如缺少必要参数
if (!config.url || config.url.includes('undefined')) {
return Promise.reject(new Error('请求地址无效'));
}
// 2. 检查 Token 是否存在
const token = getToken();
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
} else {
// 如果没有Token且需要登录,直接拦截并跳转
console.warn('Token 不存在,请求被拦截');
return Promise.reject(new Error('未登录'));
}
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
// 1. 对状态码进行过滤
if (response.status !== 200) {
// 非200视为异常
return Promise.reject(new Error(`后端返回状态码: ${response.status}`));
}
// 2. 业务状态码过滤(自定义code)
const res = response.data;
if (res.code !== 0) {
// 业务异常,统一提示
Message.error(res.message || '业务请求异常');
// 如果是登录过期 (如 code=401)
if (res.code === 401) {
logoutAndRedirect();
}
return Promise.reject(new Error(res.message));
}
return res;
},
(error) => {
// 网络异常、超时、500等 HTTP 错误
if (error.code === 'ECONNABORTED') {
Message.error('请求超时');
} else if (error.response) {
const status = error.response.status;
switch (status) {
case 401:
Message.error('未授权,请登录');
logoutAndRedirect();
break;
case 403:
Message.error('拒绝访问');
break;
case 404:
Message.error('接口不存在');
break;
case 500:
Message.error('服务器内部错误');
break;
default:
Message.error('请求失败');
}
} else {
Message.error('网络连接异常');
}
return Promise.reject(error);
}
);
export default service;
Fetch 封装拦截
原生 Fetch 没有拦截器,但可以通过封装函数实现类似效果:
async function myFetch(url, options = {}) {
// 请求前过滤
if (!url || url.startsWith('//')) {
throw new Error('无效请求 URL');
}
const token = getToken();
if (!token && options.needAuth) {
throw new Error('未登录');
}
const config = {
headers: { 'Content-Type': 'application/json', ...options.headers },
...options,
};
if (token) config.headers['Authorization'] = `Bearer ${token}`;
// 发起请求
let response;
try {
response = await fetch(url, config);
} catch (e) {
throw new Error('网络不通或请求被拦截');
}
// 响应过滤
if (!response.ok) {
if (response.status === 401) {
logoutAndRedirect();
}
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.code !== 0) {
// 业务异常过滤
throw new Error(data.message || '业务异常');
}
return data;
}
URL 过滤(前端路由守卫)
对于某些白名单外的 URL,可直接在 Vue/React Router 中拦截:
// Vue Router 导航守卫
router.beforeEach((to, from, next) => {
// 过滤非业务域名请求(比如阻止直接调用外部API)
if (to.path.startsWith('/api/external')) {
// 记录日志或阻止
console.warn('禁止访问外部API路径');
next(false);
} else {
next();
}
});
后端层面(网关/中间件)
后端是异常的最后一道防线,通常使用网关(如 Nginx、Kong、Spring Cloud Gateway)或中间件(如 Express、Flask、Spring Interceptor)进行过滤。
Nginx 网关过滤(性能最高)
Nginx 可拦截非法请求(如 SQL 注入、无效 Header、频率超限)直接返回 4xx/5xx。
# 1. 拦截不合法 URL(包含特殊字符)
if ($request_uri ~* "(\"|'|%27|%22|<|>|script|select|union)") {
return 403;
}
# 2. IP 黑名单
deny 192.168.1.100;
# 3. 限流(异常高频请求)
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
location /api/ {
limit_req zone=api_limit burst=5 nodelay;
proxy_pass http://backend;
}
# 4. 拦截特定 User-Agent(爬虫或恶意请求)
if ($http_user_agent ~* (Python-urllib|curl|wget) ) {
return 403;
}
Node.js (Express/Koa) 中间件
// 请求异常过滤中间件
const requestFilter = (req, res, next) => {
// 1. 检查请求体大小(防止超大请求)
const contentLength = parseInt(req.headers['content-length'], 10);
if (contentLength > 10 * 1024 * 1024) { // 大于10MB
return res.status(413).json({ error: '请求体过大' });
}
// 2. 检查必须的 Header
if (!req.headers['x-app-version']) {
return res.status(400).json({ error: '缺少 App Version Header' });
}
// 3. 检查 Token 有效性
const token = req.headers.authorization?.split(' ')[1];
if (req.url.startsWith('/api/protected') && !token) {
return res.status(401).json({ error: '未授权' });
}
// 4. 过滤 XSS 关键字
const body = req.body?.toString() || '';
if (/<script>|onerror=|javascript:/i.test(body)) {
return res.status(403).json({ error: '包含非法字符' });
}
next();
};
// 全局异常处理
app.use((err, req, res, next) => {
// 捕获中间件和业务异常
console.error('Request Error:', err);
res.status(err.status || 500).json({
error: err.message || '服务器内部错误',
});
});
Java Spring Boot 拦截器
@Component
public class RequestFilter implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
// 1. 黑白名单
String ip = request.getRemoteAddr();
if (ip.equals("192.168.1.100")) {
response.sendError(403, "IP被禁止");
return false;
}
// 2. 参数校验(防注入)
String queryString = request.getQueryString();
if (queryString != null && queryString.matches(".*['\"<>&].*")) {
response.sendError(400, "参数包含非法字符");
return false;
}
// 3. Token 验证
String token = request.getHeader("Authorization");
if (request.getRequestURI().startsWith("/api/private") &&
(token == null || !token.startsWith("Bearer "))) {
response.sendError(401, "Token无效");
return false;
}
return true;
}
}
后端业务层异常过滤(Database/Service)
在业务代码中通过捕获特定异常进行过滤,防止脏数据进入核心逻辑:
// 例:Spring 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<?> handleBadRequest(Exception e) {
return ResponseEntity.badRequest().body(Map.of("error", e.getMessage()));
}
@ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<?> handleAuthError() {
return ResponseEntity.status(403).body(Map.of("error", "权限不足"));
}
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<?> handleDBError() {
return ResponseEntity.status(500).body(Map.of("error", "数据异常,已拦截"));
}
}
请求前端/后端链路拦截模型
[客户端]
↓ 请求拦截(Axios/自定义Fetch)
↓ URL白名单、Token检查、参数基础校验
↓ 若异常 → 返回Promise.reject或跳转
[网络]
↓ 可能被 CDN/WAF 拦截
[网关/反向代理](Nginx/Kong)
↓ 限流、IP黑名单、非法字符过滤、Header验证
↓ 若异常 → 直接返回 429/403/400
[后端应用]
↓ 中间件/拦截器(Express/Spring Interceptor)
↓ Token解密、权限验证、参数深度校验
[业务层]
↓ 数据校验异常捕获(ControllerAdvice)
[数据库/外部服务]
最佳实践总结
| 拦截层次 | 常用工具/方法 | |
|---|---|---|
| 客户端 | Axios拦截器, Fetch封装, 前端路由守卫 | 无效URL、Token丢失、业务code异常、网络超时 |
| 网关 | Nginx/OpenResty/Kong/WAF | 恶意IP、高频请求、SQL/XSS注入、非标准HTTP方法 |
| 后端中间件 | Express中间件、SpringInterceptor、Flask装饰器 | Token解析失败、Header缺失、权限不足、请求体过大 |
| 业务代码 | 全局异常处理器、参数校验框架 | 参数格式错误、数据库约束违反、业务状态码异常 |
建议优先级:
- 首先在客户端做基础过滤(避免浪费网络请求)
- 其次在网关做流量和安全性过滤(拦截绝大多数恶意请求)
- 最后在后端中间件做严谨的权限和参数验证(安全底线)
这样通过多层过滤,可以过滤掉 99% 的异常请求,同时让真正的异常被及时捕获并返回友好提示。