A Spring Web library that intercepts and captures HTTP request/response data-including URI, path, query parameters, headers, and request/response body (including files) and publishes an event with this data.
- Automatic HTTP interception: Captures all incoming HTTP requests and outgoing responses in your Spring Boot application.
- Rich event data: Publishes events containing details such as method, path, query/path parameters, headers, and full request/response.
- Multipart & file support: Handles multipart/form-data and file uploads.
- Content type handling: Supports JSON, XML, plain text, form data, and more.
- Spring Boot integration: Provides auto-configuration for easy setup in Spring Boot projects.
- Conditional HTTP Event Publishing: Interfaces like
IHttpRequestPublishCondition
andIHttpResponsePublishCondition
allow flexible, condition-based publishing of HTTP events. - Excluded Endpoints Support: Easily configure HTTP methods and paths to exclude from event publishing.
- Extensible Publisher & Parsing: Implement your own
IHttpEventPublisher
,IRequestBodyParser
,IResponseBodyParser
,IRequestFieldCaptor
, orIResponseFieldCaptor
for custom event publication and field/body parsing.
-
Add to your Spring Boot project:
<dependency> <groupId>com.davidrandoll</groupId> <artifactId>spring-web-captor</artifactId> <version>0.0.1-beta</version> </dependency>
-
Listen for HTTP events:
Implement an event listener for
HttpRequestEvent
andHttpResponseEvent
to handle captured traffic.@EventListener public void handleRequest(HttpRequestEvent event) { // Access event.getMethod(), event.getPath(), event.getRequestBody(), etc. }
or for response body
@EventListener public void handleRequest(HttpResponseEvent event) { // Access event.getMethod(), event.getPath(), event.getResponseBody(), etc. }
By default, Spring Web Captor uses Spring's ApplicationEventPublisher
to publish web capture events. However, if you
prefer not to use ApplicationEventPublisher
, you can provide your own implementation of the IWebCaptorEventPublisher
interface.
For example, you could publish events to a message broker such as RabbitMQ, Kafka, or any other system as needed.
@Component
public class MyCustomEventPublisher implements IWebCaptorEventPublisher {
@Override
public void publishEvent(Object event) {
// Example: publish to RabbitMQ, Kafka, or any other system
System.out.println("Captured event: " + event);
}
}
You can then configure your application to use this custom publisher when setting up the web captor.
This library supports adding additional details to the request/response event using the IHttpEventExtension
interface.
You can implement this interface to enrich captured HTTP events with custom information.
For example, the provided ClientDetailsHttpEventExtension
implementation uses this interface to capture the user's IP
address and User-Agent:
public class ClientDetailsHttpEventExtension implements IHttpEventExtension {
@Override
public Map<String, Object> enrichRequestEvent(HttpServletRequest req, HttpServletResponse res, HttpRequestEvent event) {
// return a map with the user ip and user agent here
return Map.of(
"userIp", req.getRemoteAddr(),
"userAgent", req.getHeader("User-Agent")
);
}
@Override
public Map<String, Object> enrichResponseEvent(HttpServletRequest req, HttpServletResponse res, HttpRequestEvent reqEvent, HttpResponseEvent resEvent) {
// return a map with the user ip and user agent here
return Map.of(
"userIp", req.getRemoteAddr(),
"userAgent", req.getHeader("User-Agent")
);
}
}
To use your own extension, implement the IHttpEventExtension
interface and register it as a Spring bean. This allows
your additional details to be automatically included in the captured events.
When an HTTP event is published, any additional details added by your IHttpEventExtension
implementation will be
available in the event's additionalData
map. You can access them as follows:
@EventListener
public void handleHttpEvent(HttpEvent event) {
// Retrieve additional details by key from the additionalData map
Object clientIp = event.getAdditionalData().get("userIp");
Object userAgent = event.getAdditionalData().get("userAgent");
// Process the details as needed
}
Spring Web Captor allows you to customize how HTTP bodies are parsed by implementing the IRequestBodyParser
or
IResponseBodyParser
interface. This is useful if you want to support additional content types or handle
request/response bodies in a specific way.
The library provides a built-in example for parsing JSON request bodies. You can implement your own parser by following a similar pattern:
@RequiredArgsConstructor
@Order(1)
public class JsonRequestBodyParser implements IRequestBodyParser {
private final ObjectMapper objectMapper;
@Override
public boolean supports(String contentType) {
return contentType != null && contentType.contains("json");
}
@Override
public BodyPayload parse(ServletRequest request, byte[] body) throws IOException {
if (ObjectUtils.isEmpty(body)) {
return new BodyPayload(JsonNodeFactory.instance.nullNode());
}
return new BodyPayload(objectMapper.readTree(body));
}
}
@RequiredArgsConstructor
@Order(1)
public class JsonResponseBodyParser implements IResponseBodyParser {
private final ObjectMapper objectMapper;
@Override
public boolean supports(String contentType) {
return contentType != null && contentType.contains("json");
}
@Override
public BodyPayload parse(HttpServletResponse response, byte[] body) throws IOException {
if (ObjectUtils.isEmpty(body)) {
return new BodyPayload(JsonNodeFactory.instance.nullNode());
}
return new BodyPayload(objectMapper.readTree(body));
}
}
How it works:
- The
supports
method checks if theContent-Type
header includes"json"
. - If supported, the
parse
method uses Jackson'sObjectMapper
to deserialize the request body into aJsonNode
, which is then wrapped in aBodyPayload
object.
To use your own parser, implement IRequestBodyParser
or IResponseBodyParser
, and register it via the
IBodyParserRegistry.register
or injects the DefaultBodyParserRegistry
bean and call the register
method in your
configuration class.
The registry is there so that you can use the built-in parsers or your own custom parsers seamlessly.
Tip: You can provide multiple parsers for different content types (e.g., XML, protobuf, etc.) and control their order with the
@Order
annotation. By default, the library includes request body parsers for JSON, XML, multipart, x-www-form-urlencoded and a fallback parser for plain text.
Spring Web Captor gives you fine-grained control over which fields are captured from requests and responses by allowing
you to implement the IRequestFieldCaptor
and IResponseFieldCaptor
interfaces. These interfaces let you add,
transform, or filter specific fields before they are published in the event.
Suppose you want to extract a custom header ("X-Request-Token") from every incoming request and include it in the
captured event. You can implement IRequestFieldCaptor
as follows:
import com.davidrandoll.spring_web_captor.capture.IRequestFieldCaptor;
import com.davidrandoll.spring_web_captor.event.HttpRequestEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
@RequiredArgsConstructor
@Order(1)
public class XRequestTokenFieldCaptor implements IRequestFieldCaptor {
@Override
public void capture(HttpServletRequest request, HttpRequestEvent.HttpRequestEventBuilder<?, ?> builder) {
String token = servletRequest.getHeader("X-Request-Token");
if (token != null) {
builder.additionalData("xRequestToken", token);
}
}
}
Likewise, you can capture fields from the response by implementing IResponseFieldCaptor
. For example, to capture an "
X-Response-Token" header:
import com.davidrandoll.spring_web_captor.capture.IResponseFieldCaptor;
import com.davidrandoll.spring_web_captor.event.HttpRequestEvent;
import com.davidrandoll.spring_web_captor.event.HttpResponseEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
@Component
@RequiredArgsConstructor
@Order(1)
public class XResponseTokenFieldCaptor implements IResponseFieldCaptor {
@Override
public void capture(HttpServletResponse response, HttpResponseEvent.HttpResponseEventBuilder<?, ?> builder) {
String token = servletResponse.getHeader("X-Response-Token");
if (token != null) {
builder.additionalData("xResponseToken", token);
}
}
}
How it works:
- Implement the appropriate interface and annotate your class with
@Component
(and optionally@Order
). - Use the
captureFields
method to extract, transform, or add any extra information to the event’sadditionalData
map.
Tip: You can implement multiple captors and control their order of execution with the
@Order
annotation.
Spring Web Captor allows you to control exactly when HTTP request and response events are published by implementing conditional interfaces. This enables you to filter out specific requests or responses based on any logic you need (e.g., only publish events for authenticated users, or requests to certain paths).
There are two main interfaces for this purpose:
IHttpRequestPublishCondition
IHttpResponsePublishCondition
Implement either (or both) to define custom logic for event publishing.
Here's how you might implement a condition to publish events only if the user is authenticated:
@Component
@Order(1)
public class AuthenticatedRequestPublishCondition implements IHttpRequestPublishCondition {
@Override
public boolean shouldPublishRequest(HttpServletRequest request, HttpServletResponse response) {
// Example: Only publish if a user principal is present (i.e., the user is authenticated)
return request.getUserPrincipal() != null;
}
}
You can register multiple condition beans. All conditions must return true
for the event to be published (logical
AND).
Note: If you want to exclude requests to specific endpoints (such as health checks or documentation), you can do this easily using the built-in app property
web-captor.excluded-endpoints
in your configuration, without needing custom code.
Summary:
- Use
IHttpRequestPublishCondition
and/orIHttpResponsePublishCondition
for programmatic, logic-based control. - Use the
excluded-endpoints
property for simple endpoint/path/method exclusion.
-
Request:
- Method (GET, POST, PUT, PATCH, DELETE etc.)
- Full URL and Path
- Query parameters
- Path Variables
- Headers (including multiple values)
- Body (JSON, XML, form-data, files, etc.)
- custom fields added by
IRequestFieldCaptor
orIHttpEventExtension
-
Response:
- All fields from the request event
- Status code
- Headers
- Response Body
Contributions are welcome! If you have suggestions for improvements or bug fixes, feel free to open an issue or submit a pull request.
To contribute:
- Fork the repository.
- Create a new branch for your feature or bugfix.
- Make your changes and include tests if applicable.
- Open a pull request describing your changes.
Please ensure your code follows the existing style and passes any automated checks.
Thank you for helping improve this project!
MIT License
Author: david-randoll