一、当HTTP请求遇上Spring Boot
某天老王在调试接口时突然发现:前端传来的中文参数在后端全变成问号,客户端看到的响应内容也莫名多出
二、过滤器知识精讲室
2.1 过滤器原理大白话
想象机场安检流程:旅客(请求)进入候机厅前要过安检仪(过滤器),登机后行李还要二次检查(响应处理)。Spring Boot过滤器的工作机制正是:
请求 → FilterChain → Controller → FilterChain → 响应
每个过滤器像尽职的安检员,有序检查并处理流经的每个请求和响应。
2.2 技术选型指南针
虽然Servlet Filter是基础解决方案,但开发者常面临选择困境:
- 原生Filter:轻量但功能单一
- Spring Interceptor:能获取上下文但无法修改响应体
- AOP:适合业务处理但不够底层
本次我们选择Servlet Filter方案,原因在于其对请求响应流的完全控制能力。
三、实战代码实验室
3.1 字符编码净化器
(核心示例)
// 基于Jakarta Servlet 5.0 + Spring Boot 3.x
@WebFilter(urlPatterns = "/*")
public class EncodingFilter implements Filter {
// 字符集白名单
private static final Set<String> ALLOWED_ENCODINGS =
Set.of("UTF-8", "GB18030", "BIG5");
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 请求预处理
HttpServletRequest req = (HttpServletRequest) request;
String reqEncoding = detectRequestEncoding(req);
if (!ALLOWED_ENCODINGS.contains(reqEncoding.toUpperCase())) {
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("不支持的字符编码格式");
return;
}
// 统一设置字符集
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
// 包装响应对象实现写入时编码校验
ResponseWrapper wrapper = new ResponseWrapper((HttpServletResponse) response);
try {
chain.doFilter(request, wrapper);
} finally {
// 响应后处理
String responseContent = wrapper.getContent();
validateEncoding(responseContent);
response.getWriter().write(responseContent);
}
}
// 省略辅助方法实现...
}
// 自定义响应包装器
class ResponseWrapper extends HttpServletResponseWrapper {
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public PrintWriter getWriter() {
return new PrintWriter(new OutputStreamWriter(buffer, StandardCharsets.UTF_8));
}
public String getContent() {
try {
return buffer.toString(StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("编码转换异常", e);
}
}
}
3.2 跨域处理增强版
// 处理OPTIONS预检请求的过滤器
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
四、工业级应用蓝图
4.1 典型应用场景
- API网关预处理:某金融系统在网关层统一过滤异常参数
- 全局安全控制:某电商平台通过过滤器验证请求签名
- 智能路由分发:根据请求特征分流至不同服务集群
- 敏感词过滤:某社交平台实现实时内容净化
4.2 双刃剑启示录
优势侧写:
- 系统解耦的典范(认证/日志等模块独立)
- 非侵入式改造能力
- 全链路可视化的基石
短板警示:
- 过滤器顺序如同列车时刻表(错序即翻车)
- 性能悬崖(某电商曾因多层过滤损失15%吞吐量)
- 异常处理黑洞(未捕获的异常直接返回500)
五、避雷备忘录
- 顺序迷局:使用@Order注解时要记住数字越小优先级越高
- 线程陷阱:避免在过滤器中修改共享变量(必要时用ThreadLocal)
- 性能禁区:压缩过滤器耗时(某案例:1秒超时设置下,过滤器链总耗时需<800ms)
- 字符集彩蛋:注意XML格式的特殊编码声明规则
- 流数据魔咒:处理multipart/form-data时要跳过字符集设置
六、未来演进风向标
在云原生时代,过滤器正朝着智能化方向发展。某云厂商最新案例:通过AI过滤器实时分析请求特征,动态调整安全策略。新技术轮替中,WebFlux的WebFilter正在逐步替代传统方案,但Servlet Filter仍将在未来5年内保持重要地位。