Spring中如何审计端点通信?获取交互JSON并存储至数据库
Hey there! Let's walk through how to capture that JSON data from endpoint interactions and feed it into Javers for auditing. I'll focus on practical, actionable steps—especially since Javers is commonly used in Java/Spring ecosystems, I'll use that as the primary example.
Step 1: Capture Request/Response Data
First, you need a way to intercept incoming requests and outgoing responses to extract their JSON payloads. Here are the most reliable approaches:
Option 1: Spring Interceptors + Content Caching
Spring provides built-in wrappers to cache request/response bodies (since they can only be read once by default). Create a custom interceptor to handle this:
@Component public class EndpointAuditInterceptor implements HandlerInterceptor { private final ObjectMapper objectMapper; private final Javers javers; // Inject dependencies via constructor public EndpointAuditInterceptor(ObjectMapper objectMapper, Javers javers) { this.objectMapper = objectMapper; this.javers = javers; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // Wrap request to cache body for later reading ContentCachingRequestWrapper cachedRequest = new ContentCachingRequestWrapper(request); request.setAttribute("cachedRequest", cachedRequest); // Wrap response to capture its output ContentCachingResponseWrapper cachedResponse = new ContentCachingResponseWrapper(response); request.setAttribute("cachedResponse", cachedResponse); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { ContentCachingRequestWrapper cachedRequest = (ContentCachingRequestWrapper) request.getAttribute("cachedRequest"); ContentCachingResponseWrapper cachedResponse = (ContentCachingResponseWrapper) request.getAttribute("cachedResponse"); // Extract request/response bodies as strings String requestBody = new String(cachedRequest.getContentAsByteArray(), cachedRequest.getCharacterEncoding()); String responseBody = new String(cachedResponse.getContentAsByteArray(), cachedResponse.getCharacterEncoding()); // Critical: Copy cached response back to original so clients receive the actual response cachedResponse.copyBodyToResponse(); // Create an audit record entity to store interaction details EndpointAuditRecord auditRecord = new EndpointAuditRecord(); auditRecord.setRequestUrl(request.getRequestURI()); auditRecord.setHttpMethod(request.getMethod()); auditRecord.setRequestBody(requestBody); auditRecord.setResponseBody(responseBody); auditRecord.setTimestamp(LocalDateTime.now()); auditRecord.setStatus(response.getStatus()); // Commit the record to Javers—this stores a full snapshot of the entity javers.commit("system-auditor", auditRecord); } }
Don't forget to register the interceptor in your Spring config:
@Configuration public class WebConfig implements WebMvcConfigurer { private final EndpointAuditInterceptor auditInterceptor; public WebConfig(EndpointAuditInterceptor auditInterceptor) { this.auditInterceptor = auditInterceptor; } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(auditInterceptor) .addPathPatterns("/**"); // Adjust paths to target only your desired endpoints } }
Option 2: API Gateway Level Interception
If you're using an API gateway (like Spring Cloud Gateway), intercept all traffic at the gateway layer—this is cleaner for multi-service setups, since you don't need to add interceptors to each individual service. Use a GlobalFilter to capture request/response bodies similarly to the interceptor approach.
Option 3: AOP Aspect
For granular control (e.g., auditing only specific controller methods), use a Spring AOP aspect with @Around advice to wrap controller method calls and capture input/output directly.
Step 2: Integrate with Javers
Once you have the interaction data, Javers simplifies storing and querying audit snapshots. Here's what you need:
- Define an Audit Entity: Create a simple POJO to represent your endpoint interaction (like
EndpointAuditRecordin the example above). Javers will handle storing its full state in your database. - Configure Javers: Set up Javers to use your target database (e.g., JPA for SQL databases):
@Bean public Javers javers(EntityManager entityManager) { return JaversBuilder.javers() .registerJaversRepository(JpaJaversRepository.builder().entityManager(entityManager).build()) .withObjectAccessHook(new JpaAccessHook()) .build(); }
- Commit Records: Use
javers.commit()to save each audit record. Javers will store a snapshot of the entity, including all fields like request body, response body, and timestamp.
Key Considerations
- Sensitive Data: Always filter or mask sensitive fields (passwords, tokens, PII) before storing. Use Jackson annotations like
@JsonIgnoreor custom serializers to scrub data. - Performance: For high-traffic systems, use async processing (e.g.,
@Asyncon audit logic or a message queue like Kafka) to avoid blocking request processing. - Querying History: Later, use Javers' query API to retrieve audit history—e.g., find all interactions for a specific endpoint, or track changes in response payloads over time.
内容的提问来源于stack exchange,提问作者Rodolfo

