【学习】过滤器与拦截器详解:Web开发中的请求处理机制
前言
在Web开发中,过滤器(Filter)和拦截器(Interceptor)是两个重要的概念,它们都可以在请求处理过程中进行拦截和处理,但在实现机制、作用范围和使用场景上存在显著差异。本文将详细介绍过滤器和拦截器的概念、区别、应用场景以及具体的实现方式,帮助开发者更好地理解和使用这两种技术。
一、过滤器(Filter)详解
(一)过滤器的基本概念
过滤器是Java Servlet规范中定义的组件,它可以在请求到达Servlet之前或响应离开Servlet之后对请求和响应进行预处理和后处理。过滤器基于函数回调机制,是面向切面编程(AOP)思想的体现。
1. 过滤器的特点
- 基于Servlet规范:过滤器是Servlet容器提供的功能
- 作用于整个Web应用:可以拦截所有进入应用的请求
- 链式调用:多个过滤器可以形成过滤器链
- 容器级别:在Servlet容器层面工作
2. 过滤器的生命周期
public interface Filter {
// 初始化方法,容器启动时调用
void init(FilterConfig filterConfig) throws ServletException;
// 过滤方法,每次请求时调用
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
// 销毁方法,容器关闭时调用
void destroy();
}
(二)过滤器的实现方式
1. 传统Servlet方式实现
// 字符编码过滤器示例
@WebFilter(urlPatterns = "/*", filterName = "encodingFilter")
public class EncodingFilter implements Filter {
private String encoding = "UTF-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 从配置中获取编码格式
String configEncoding = filterConfig.getInitParameter("encoding");
if (configEncoding != null && !configEncoding.isEmpty()) {
this.encoding = configEncoding;
}
System.out.println("EncodingFilter初始化,编码格式: " + encoding);
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("EncodingFilter - 请求前处理");
// 设置请求和响应的字符编码
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=" + encoding);
// 继续执行过滤器链
chain.doFilter(request, response);
System.out.println("EncodingFilter - 响应后处理");
}
@Override
public void destroy() {
System.out.println("EncodingFilter销毁");
}
}
2. Spring Boot方式实现
// 日志记录过滤器
@Component
public class LoggingFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 记录请求信息
String requestURI = httpRequest.getRequestURI();
String method = httpRequest.getMethod();
String remoteAddr = httpRequest.getRemoteAddr();
long startTime = System.currentTimeMillis();
logger.info("请求开始 - URI: {}, Method: {}, IP: {}", requestURI, method, remoteAddr);
try {
// 继续执行过滤器链
chain.doFilter(request, response);
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("请求结束 - URI: {}, Status: {}, Duration: {}ms",
requestURI, httpResponse.getStatus(), duration);
}
}
}
// 过滤器配置类
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<LoggingFilter> loggingFilter() {
FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new LoggingFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1); // 设置过滤器执行顺序
return registrationBean;
}
@Bean
public FilterRegistrationBean<CorsFilter> corsFilter() {
FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CorsFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(2);
return registrationBean;
}
}
3. 跨域处理过滤器
// CORS跨域过滤器
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 设置CORS响应头
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS");
httpResponse.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With");
httpResponse.setHeader("Access-Control-Max-Age", "3600");
// 处理预检请求
if ("OPTIONS".equalsIgnoreCase(httpRequest.getMethod())) {
httpResponse.setStatus(HttpServletResponse.SC_OK);
return;
}
chain.doFilter(request, response);
}
}
(三)过滤器的应用场景
- 字符编码设置:统一设置请求和响应的字符编码
- 跨域处理:处理CORS跨域请求
- 请求日志记录:记录请求的详细信息
- 安全检查:进行基础的安全验证
- 请求参数预处理:对请求参数进行统一处理
- 响应数据压缩:对响应数据进行压缩处理
二、拦截器(Interceptor)详解
(一)拦截器的基本概念
拦截器是Spring框架提供的组件,它基于Java的反射机制和动态代理技术实现。拦截器主要用于拦截Controller的请求,可以在请求处理的不同阶段进行干预。
1. 拦截器的特点
- 基于Spring框架:是Spring MVC的组件
- 作用于Controller层:只能拦截进入Controller的请求
- 更细粒度的控制:可以获取到Handler和ModelAndView
- 框架级别:在Spring MVC框架层面工作
2. 拦截器的接口定义
public interface HandlerInterceptor {
// 在Controller方法执行前调用
default boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
return true;
}
// 在Controller方法执行后,视图渲染前调用
default void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
}
// 在整个请求完成后调用
default void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
}
}
(二)拦截器的实现方式
1. 基础拦截器实现
// 登录验证拦截器
@Component
public class LoginInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
String requestURI = request.getRequestURI();
logger.info("LoginInterceptor - 拦截请求: {}", requestURI);
// 排除不需要登录验证的路径
if (isExcludePath(requestURI)) {
return true;
}
// 检查用户是否登录
HttpSession session = request.getSession();
Object user = session.getAttribute("user");
if (user == null) {
logger.warn("用户未登录,拒绝访问: {}", requestURI);
// 判断是否为AJAX请求
if (isAjaxRequest(request)) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":401,\"message\":\"未登录\"}");
} else {
response.sendRedirect("/login");
}
return false;
}
logger.info("用户已登录,允许访问: {}", requestURI);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if (modelAndView != null) {
// 可以在这里添加通用的模型数据
modelAndView.addObject("currentTime", new Date());
logger.info("PostHandle - 添加通用模型数据");
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
if (ex != null) {
logger.error("请求处理异常: {}", ex.getMessage(), ex);
}
logger.info("AfterCompletion - 请求处理完成: {}", request.getRequestURI());
}
/**
* 判断是否为排除路径
*/
private boolean isExcludePath(String requestURI) {
String[] excludePaths = {"/login", "/register", "/static", "/css", "/js", "/images"};
for (String path : excludePaths) {
if (requestURI.startsWith(path)) {
return true;
}
}
return false;
}
/**
* 判断是否为AJAX请求
*/
private boolean isAjaxRequest(HttpServletRequest request) {
String requestedWith = request.getHeader("X-Requested-With");
return "XMLHttpRequest".equals(requestedWith);
}
}
2. 权限验证拦截器
// 权限验证拦截器
@Component
public class AuthorityInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(AuthorityInterceptor.class);
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 只处理Controller方法
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 检查方法是否需要权限验证
RequirePermission requirePermission = handlerMethod.getMethodAnnotation(RequirePermission.class);
if (requirePermission == null) {
// 检查类级别的注解
requirePermission = handlerMethod.getBeanType().getAnnotation(RequirePermission.class);
}
if (requirePermission == null) {
return true; // 不需要权限验证
}
// 获取当前用户
HttpSession session = request.getSession();
User currentUser = (User) session.getAttribute("user");
if (currentUser == null) {
logger.warn("用户未登录,拒绝访问");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "未登录");
return false;
}
// 检查用户权限
String[] requiredPermissions = requirePermission.value();
boolean hasPermission = userService.hasAnyPermission(currentUser.getId(), requiredPermissions);
if (!hasPermission) {
logger.warn("用户 {} 没有访问权限: {}", currentUser.getUsername(),
Arrays.toString(requiredPermissions));
response.sendError(HttpServletResponse.SC_FORBIDDEN, "权限不足");
return false;
}
logger.info("用户 {} 权限验证通过", currentUser.getUsername());
return true;
}
}
// 权限注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequirePermission {
String[] value();
}
3. 性能监控拦截器
// 性能监控拦截器
@Component
public class PerformanceInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(PerformanceInterceptor.class);
private static final String START_TIME_ATTRIBUTE = "startTime";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute(START_TIME_ATTRIBUTE, startTime);
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String className = handlerMethod.getBeanType().getSimpleName();
String methodName = handlerMethod.getMethod().getName();
logger.info("开始执行: {}.{}", className, methodName);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
Long startTime = (Long) request.getAttribute(START_TIME_ATTRIBUTE);
if (startTime != null) {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
String className = handlerMethod.getBeanType().getSimpleName();
String methodName = handlerMethod.getMethod().getName();
logger.info("执行完成: {}.{}, 耗时: {}ms", className, methodName, duration);
// 如果执行时间过长,记录警告
if (duration > 1000) {
logger.warn("慢请求警告: {}.{}, 耗时: {}ms", className, methodName, duration);
}
}
}
}
}
4. 拦截器配置
// 拦截器配置类
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Autowired
private AuthorityInterceptor authorityInterceptor;
@Autowired
private PerformanceInterceptor performanceInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 性能监控拦截器 - 最高优先级
registry.addInterceptor(performanceInterceptor)
.addPathPatterns("/**")
.order(1);
// 登录验证拦截器
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register", "/static/**", "/error")
.order(2);
// 权限验证拦截器
registry.addInterceptor(authorityInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login", "/register", "/static/**", "/error")
.order(3);
}
}
(三)拦截器的应用场景
- 登录验证:检查用户是否已登录
- 权限控制:验证用户是否有访问特定资源的权限
- 性能监控:监控Controller方法的执行时间
- 操作日志:记录用户的操作行为
- 参数验证:对请求参数进行统一验证
- 国际化处理:根据用户设置切换语言
三、过滤器与拦截器的对比
(一)主要区别
特性 | 过滤器(Filter) | 拦截器(Interceptor) |
---|---|---|
实现基础 | Servlet规范 | Spring框架 |
作用范围 | 整个Web应用 | Spring MVC的Controller |
执行时机 | Servlet容器级别 | Spring框架级别 |
配置方式 | web.xml或@WebFilter | 实现WebMvcConfigurer |
获取Spring Bean | 需要特殊处理 | 可以直接注入 |
异常处理 | 无法捕获Controller异常 | 可以在afterCompletion中处理 |
执行顺序 | 在拦截器之前 | 在过滤器之后 |
(二)执行流程对比
请求流程:
Client Request
↓
Filter1.doFilter() - 前置处理
↓
Filter2.doFilter() - 前置处理
↓
DispatcherServlet
↓
Interceptor1.preHandle()
↓
Interceptor2.preHandle()
↓
Controller.method()
↓
Interceptor2.postHandle()
↓
Interceptor1.postHandle()
↓
View Rendering
↓
Interceptor2.afterCompletion()
↓
Interceptor1.afterCompletion()
↓
Filter2.doFilter() - 后置处理
↓
Filter1.doFilter() - 后置处理
↓
Client Response
(三)选择建议
1. 使用过滤器的场景
- 字符编码设置:需要在整个请求处理过程中生效
- 跨域处理:需要在Servlet容器级别处理
- 安全过滤:如XSS防护、SQL注入防护
- 请求日志:记录所有进入应用的请求
- 静态资源处理:需要处理静态资源请求
2. 使用拦截器的场景
- 登录验证:只需要验证Controller请求
- 权限控制:基于注解的细粒度权限控制
- 操作日志:记录用户的业务操作
- 性能监控:监控Controller方法执行时间
- 数据预处理:需要访问Spring容器中的Bean
四、实际应用案例
(一)完整的Web应用安全架构
// 1. 安全过滤器 - 处理基础安全
@Component
public class SecurityFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// XSS防护
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(httpRequest);
// 设置安全响应头
httpResponse.setHeader("X-Content-Type-Options", "nosniff");
httpResponse.setHeader("X-Frame-Options", "DENY");
httpResponse.setHeader("X-XSS-Protection", "1; mode=block");
chain.doFilter(xssRequest, response);
}
}
// 2. 登录拦截器 - 处理用户认证
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
@Autowired
private TokenService tokenService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 获取token
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
token = token.substring(7);
}
// 验证token
if (token == null || !tokenService.validateToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("{\"error\":\"Invalid token\"}");
return false;
}
// 设置用户信息到请求上下文
User user = tokenService.getUserFromToken(token);
UserContext.setCurrentUser(user);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 清理用户上下文
UserContext.clear();
}
}
// 3. 权限拦截器 - 处理用户授权
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequireRole requireRole = handlerMethod.getMethodAnnotation(RequireRole.class);
if (requireRole != null) {
User currentUser = UserContext.getCurrentUser();
if (!hasRequiredRole(currentUser, requireRole.value())) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write("{\"error\":\"Access denied\"}");
return false;
}
}
return true;
}
private boolean hasRequiredRole(User user, String[] requiredRoles) {
// 实现角色验证逻辑
return Arrays.stream(requiredRoles)
.anyMatch(role -> user.getRoles().contains(role));
}
}
(二)API接口监控系统
// API监控拦截器
@Component
public class ApiMonitorInterceptor implements HandlerInterceptor {
@Autowired
private ApiMonitorService apiMonitorService;
private static final String API_MONITOR_KEY = "apiMonitor";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
ApiMonitor apiMonitor = handlerMethod.getMethodAnnotation(ApiMonitor.class);
if (apiMonitor != null) {
ApiMonitorInfo monitorInfo = new ApiMonitorInfo();
monitorInfo.setApiName(apiMonitor.value());
monitorInfo.setStartTime(System.currentTimeMillis());
monitorInfo.setRequestUri(request.getRequestURI());
monitorInfo.setMethod(request.getMethod());
monitorInfo.setUserAgent(request.getHeader("User-Agent"));
monitorInfo.setClientIp(getClientIp(request));
request.setAttribute(API_MONITOR_KEY, monitorInfo);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
ApiMonitorInfo monitorInfo = (ApiMonitorInfo) request.getAttribute(API_MONITOR_KEY);
if (monitorInfo != null) {
monitorInfo.setEndTime(System.currentTimeMillis());
monitorInfo.setDuration(monitorInfo.getEndTime() - monitorInfo.getStartTime());
monitorInfo.setStatusCode(response.getStatus());
monitorInfo.setSuccess(ex == null && response.getStatus() < 400);
if (ex != null) {
monitorInfo.setErrorMessage(ex.getMessage());
}
// 异步保存监控数据
apiMonitorService.saveMonitorInfo(monitorInfo);
}
}
private String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
// API监控注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiMonitor {
String value() default "";
}
// 监控信息实体
public class ApiMonitorInfo {
private String apiName;
private long startTime;
private long endTime;
private long duration;
private String requestUri;
private String method;
private String userAgent;
private String clientIp;
private int statusCode;
private boolean success;
private String errorMessage;
// getter和setter方法省略
}
五、最佳实践与注意事项
(一)性能优化建议
1. 过滤器优化
// 高效的过滤器实现
@Component
public class OptimizedFilter implements Filter {
// 使用缓存避免重复计算
private final Set<String> excludePaths = new HashSet<>(Arrays.asList(
"/static", "/css", "/js", "/images", "/favicon.ico"
));
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
// 快速排除静态资源
if (isStaticResource(requestURI)) {
chain.doFilter(request, response);
return;
}
// 执行业务逻辑
doBusinessLogic(httpRequest, (HttpServletResponse) response);
chain.doFilter(request, response);
}
private boolean isStaticResource(String requestURI) {
return excludePaths.stream().anyMatch(requestURI::startsWith);
}
private void doBusinessLogic(HttpServletRequest request, HttpServletResponse response) {
// 业务逻辑实现
}
}
2. 拦截器优化
// 高效的拦截器实现
@Component
public class OptimizedInterceptor implements HandlerInterceptor {
// 使用ThreadLocal缓存计算结果
private static final ThreadLocal<Boolean> authCache = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
// 检查缓存
Boolean cached = authCache.get();
if (cached != null) {
return cached;
}
// 执行验证逻辑
boolean result = performAuthentication(request);
// 缓存结果
authCache.set(result);
return result;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
// 清理ThreadLocal
authCache.remove();
}
private boolean performAuthentication(HttpServletRequest request) {
// 认证逻辑实现
return true;
}
}
(二)异常处理
// 全局异常处理拦截器
@Component
public class ExceptionHandlingInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(ExceptionHandlingInterceptor.class);
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception {
if (ex != null) {
// 记录异常信息
logger.error("请求处理异常 - URI: {}, Method: {}, Error: {}",
request.getRequestURI(), request.getMethod(), ex.getMessage(), ex);
// 根据异常类型进行不同处理
if (ex instanceof AuthenticationException) {
handleAuthenticationException(response, ex);
} else if (ex instanceof AuthorizationException) {
handleAuthorizationException(response, ex);
} else {
handleGenericException(response, ex);
}
}
}
private void handleAuthenticationException(HttpServletResponse response, Exception ex)
throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Authentication failed\"}");
}
private void handleAuthorizationException(HttpServletResponse response, Exception ex)
throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Access denied\"}");
}
private void handleGenericException(HttpServletResponse response, Exception ex)
throws IOException {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"Internal server error\"}");
}
}
(三)注意事项
1. 执行顺序
- 过滤器的执行顺序由注册顺序决定
- 拦截器的执行顺序可以通过order属性控制
- preHandle按顺序执行,postHandle和afterCompletion按逆序执行
2. 异常处理
- 过滤器中的异常需要自行处理
- 拦截器可以在afterCompletion中处理Controller抛出的异常
- 建议使用全局异常处理器配合拦截器使用
3. 性能考虑
- 避免在过滤器和拦截器中执行耗时操作
- 合理使用缓存减少重复计算
- 及时清理ThreadLocal变量避免内存泄漏
4. 安全考虑
- 敏感信息不要在日志中输出
- 验证用户输入防止注入攻击
- 合理设置会话超时时间
六、总结
过滤器和拦截器是Web开发中重要的组件,它们各有特点和适用场景:
(一)过滤器的优势
- 作用范围广:可以拦截所有进入应用的请求
- 标准化:基于Servlet规范,具有良好的兼容性
- 执行时机早:在Spring框架之前执行
- 适合基础处理:如编码设置、跨域处理等
(二)拦截器的优势
- Spring集成:可以方便地使用Spring的功能
- 细粒度控制:可以获取到具体的Handler信息
- 灵活的执行时机:提供三个执行时机的回调
- 适合业务处理:如权限验证、操作日志等
(三)选择原则
- 通用性需求:选择过滤器
- 业务相关需求:选择拦截器
- 需要Spring支持:选择拦截器
- 静态资源处理:选择过滤器
在实际项目中,通常会同时使用过滤器和拦截器,形成完整的请求处理链,以满足不同层次的需求。合理使用这两种技术,可以让我们的Web应用更加健壮、安全和高效。