后端拦截器
# Spring Boot 中的拦截器
前言
在 Spring Boot 中,拦截器(Interceptor)是一种用于拦截和处理 HTTP 请求的机制,可以在请求到达 Controller 之前或响应返回之前进行处理。拦截器可以用于记录日志、权限校验、修改请求或响应数据等。
# 一、Spring Boot 中的拦截器概述
Spring 提供了基于 HandlerInterceptor
接口的拦截器机制。拦截器可以在以下三个阶段进行处理:
preHandle
:在请求处理之前进行调用(Controller 方法调用之前)。postHandle
:在请求处理之后调用(Controller 方法调用之后,但在视图渲染之前)。afterCompletion
:在整个请求结束之后调用(视图渲染之后),常用于资源清理。
# 二、实现拦截器的几种方式
# 1. 基于 HandlerInterceptor
接口实现自定义拦截器
代码示例:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
// 在请求处理之前进行拦截
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Pre Handle method is Calling");
// 返回 true 表示继续处理请求,返回 false 则中断请求
return true;
}
// 在请求处理之后,但在视图渲染之前进行拦截
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Post Handle method is Calling");
}
// 在请求处理完成之后调用,常用于资源清理
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
System.out.println("Request and Response is completed");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
关键点:
preHandle
方法:用于在请求进入 Controller 之前进行处理,返回true
表示继续处理请求,返回false
则中断请求。postHandle
方法:用于在请求处理完毕后但在视图渲染之前进行处理,可用于修改模型数据或视图。afterCompletion
方法:用于在整个请求处理完成后进行处理,适合用于资源清理、日志记录等操作。
# 2. 注册拦截器
在 Spring Boot 中,拦截器需要通过配置类进行注册。
代码示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor; // 注入自定义拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器,并指定拦截路径
registry.addInterceptor(myInterceptor)
.addPathPatterns("/api/**") // 拦截的路径
.excludePathPatterns("/api/login", "/api/register"); // 排除的路径
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
关键配置项:
addInterceptor
:注册自定义拦截器。addPathPatterns
:指定需要拦截的路径模式。excludePathPatterns
:指定不需要拦截的路径。
# 3. 基于 HandlerInterceptorAdapter
(已过时)
HandlerInterceptorAdapter
是 Spring 早期提供的简化拦截器实现的适配器类,但在 Spring 5.3 之后被标记为已过时。现在推荐直接实现 HandlerInterceptor
接口。
# 三、拦截器中的常用 API 和参数说明
HttpServletRequest
和HttpServletResponse
:- 可以通过这两个对象获取请求参数、请求头、Session、响应状态码等信息。
request.getRequestURI()
:获取请求的 URI。request.getMethod()
:获取请求方法(如GET
、POST
)。response.setStatus(int status)
:设置响应状态码。
Object handler
:- 代表当前请求的处理器(Controller 方法),可以用于判断当前请求的目标。
ModelAndView
(在postHandle
中使用):- 可以通过
ModelAndView
修改视图和模型数据。
- 可以通过
# 四、拦截器的应用场景
在企业级应用中,拦截器(Interceptor)广泛用于以下几种常见场景:
- 用户认证与权限验证:在处理请求前验证用户是否登录,是否有访问权限。
- 请求日志记录:记录每次请求的详细信息,方便后续分析和排查问题。
- 数据加密与解密:在请求到达 Controller 前对敏感数据进行解密,响应返回前进行加密。
- 全局异常处理:统一捕获和处理应用中的异常,并返回友好的错误提示。
# 1. 用户认证与权限验证拦截器
在处理请求前验证用户是否已登录,并根据用户的角色或权限判断是否可以访问目标资源。
代码示例:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用户认证与权限验证拦截器。
*/
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
/**
* 处理请求前的认证逻辑。
* @param request 当前的 HttpServletRequest 对象
* @param response 当前的 HttpServletResponse 对象
* @param handler 目标处理器对象
* @return 返回 true 表示继续处理请求,false 表示请求被拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 模拟获取 Token,并验证是否有效
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
// 如果 Token 无效,返回未授权状态码
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("未授权,禁止访问!");
return false;
}
// 如果认证通过,继续处理请求
return true;
}
/**
* 校验 Token 是否有效(示例方法)。
* @param token 待校验的 Token
* @return Token 是否有效
*/
private boolean isValidToken(String token) {
// 在实际应用中,这里应校验 Token 的有效性,如解析 JWT、查询 Redis 等
return "valid-token".equals(token);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
关键点:
request.getHeader("Authorization")
:获取请求头中的认证信息。response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
:当用户未通过认证时,返回 401 状态码。- 应用场景:适用于保护需要认证的 API 资源。
# 2. 请求日志记录拦截器
记录每次请求的详细信息,包括请求时间、请求路径、请求参数、处理耗时等。
代码示例:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.logging.Logger;
/**
* 请求日志记录拦截器。
*/
@Component
public class LoggingInterceptor implements HandlerInterceptor {
private static final Logger logger = Logger.getLogger(LoggingInterceptor.class.getName());
/**
* 记录请求开始时间。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 记录请求开始时间
request.setAttribute("startTime", System.currentTimeMillis());
logger.info("请求开始: " + LocalDateTime.now());
logger.info("请求路径: " + request.getRequestURI());
logger.info("请求方法: " + request.getMethod());
// 记录请求头信息
Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = headers.nextElement();
logger.info(headerName + ": " + request.getHeader(headerName));
}
return true;
}
/**
* 记录请求完成时间及耗时。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("请求结束: " + LocalDateTime.now());
logger.info("请求耗时: " + duration + " ms");
if (ex != null) {
logger.severe("请求异常: " + ex.getMessage());
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
关键点:
request.getRequestURI()
:获取请求的路径。request.setAttribute("startTime", System.currentTimeMillis())
:记录请求的开始时间,用于计算处理耗时。- 应用场景:适用于记录请求日志,帮助分析请求性能或排查问题。
# 3. 数据加密与解密拦截器
在请求进入 Controller 前,对敏感数据进行解密;在响应返回前,对敏感数据进行加密。
代码示例:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 数据加密与解密拦截器。
*/
@Component
public class EncryptionInterceptor implements HandlerInterceptor {
/**
* 请求前解密处理。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取请求中的加密数据,并进行解密
String encryptedData = request.getParameter("data");
if (encryptedData != null) {
String decryptedData = decrypt(encryptedData);
// 将解密后的数据放回请求中,供后续处理
request.setAttribute("decryptedData", decryptedData);
}
return true;
}
/**
* 响应前加密处理。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 获取响应数据并进行加密
String responseData = (String) request.getAttribute("responseData");
if (responseData != null) {
String encryptedData = encrypt(responseData);
response.getWriter().write(encryptedData);
}
}
/**
* 数据解密逻辑(示例方法)。
*/
private String decrypt(String data) {
// 实际开发中应使用加密算法解密数据
return "解密后的数据: " + data;
}
/**
* 数据加密逻辑(示例方法)。
*/
private String encrypt(String data) {
// 实际开发中应使用加密算法加密数据
return "加密后的数据: " + data;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
关键点:
request.getParameter("data")
:获取请求参数中的加密数据。response.getWriter().write(encryptedData)
:将加密后的响应数据写入响应体。- 应用场景:适用于对涉及敏感数据的接口进行安全处理。
# 4. 全局异常处理拦截器
统一捕获系统中的异常,返回统一格式的错误响应。
代码示例:
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
/**
* 全局异常处理拦截器。
*/
@Component
public class GlobalExceptionInterceptor implements HandlerInterceptor {
/**
* 处理请求完成后的异常。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
if (ex != null) {
// 设置响应状态码
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
// 返回统一格式的错误消息
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"error\":\"服务器内部错误\",\"message\":\"" + ex.getMessage() + "\"}");
response.getWriter().flush();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
关键点:
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value())
:设置 HTTP 500 状态码。response.setContentType("application/json;charset=UTF-8")
:设置响应内容类型为 JSON 格式。- 应用场景:适用于统一处理全局异常,提升用户体验。
# 5. 拦截器的注册与配置
在 Spring Boot 中,拦截器需要通过配置类进行注册,确保在合适的请求路径上生效。
代码示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 拦截器配置类,用于注册全局拦截器。
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthenticationInterceptor authenticationInterceptor;
@Autowired
private LoggingInterceptor loggingInterceptor;
@Autowired private EncryptionInterceptor encryptionInterceptor;
@Autowired
private GlobalExceptionInterceptor globalExceptionInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册认证拦截器
registry.addInterceptor(authenticationInterceptor)
.addPathPatterns("/api/**") // 拦截所有 /api/** 路径下的请求
.excludePathPatterns("/api/public/**"); // 排除不需要拦截的路径
// 注册日志拦截器
registry.addInterceptor(loggingInterceptor)
.addPathPatterns("/**"); // 拦截所有请求
// 注册加密拦截器
registry.addInterceptor(encryptionInterceptor)
.addPathPatterns("/api/secure/**"); // 只拦截特定路径
// 注册全局异常处理拦截器
registry.addInterceptor(globalExceptionInterceptor)
.addPathPatterns("/**"); // 拦截所有请求
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
关键点:
registry.addInterceptor()
:注册拦截器。addPathPatterns()
:指定需要拦截的路径。excludePathPatterns()
:指定不需要拦截的路径。- 应用场景:配置不同的拦截器,确保在适当的路径上生效。
# 五、拦截器与过滤器的区别
- 执行顺序:过滤器是 Servlet 规范的一部分,优先于拦截器执行;拦截器是在 Spring MVC 中的执行流程。
- 使用范围:过滤器可以处理所有进入 Spring 容器的请求,而拦截器主要用于拦截进入 Spring MVC 的请求。
总结
- 拦截器是 Spring Boot 中非常强大的功能,适用于多种场景的请求预处理、后处理和资源清理。
- 通过实现
HandlerInterceptor
接口,并在配置类中进行注册,可以灵活地对请求进行拦截和处理。 - 拦截器可以在 Controller 之前、之后,甚至在视图渲染之后进行处理,具有很大的灵活性。
编辑此页 (opens new window)
上次更新: 2024/12/28, 18:32:08