英文:
Logging both ClientHttpRequestInterceptor and HttpServletRequest (or HandlerInterceptor)
问题
I want to get HttpServletRequest
information in interceptor class.
Or another word, I want to track both my API and 3rd-API.
我想在拦截器类中获取HttpServletRequest
的信息。
换句话说,我想追踪我的API和第三方API。
英文:
I'm developing an API using Spring Boot 3.1.0 to crawl data, I called this localhost:8080/crawl
. Inside this, I also use RestTemplate
to call an external API called third-party.com/data
.
I want to track API calls both my URL and third-party URL.
Here is my table in Oracle:
create table API_CALLS_TRACKING
(
ID NUMBER(20) not null
constraint API_CALLS_TRACKING_PK
primary key,
CLIENT_USERNAME VARCHAR2(20),
FROM_IP VARCHAR2(30),
API_URI VARCHAR2(100),
REQUEST_METHOD VARCHAR2(10),
QUERY_PARAMS VARCHAR2(200),
PATH_PARAMS VARCHAR2(500),
REQUEST_PAYLOAD VARCHAR2(500),
USER_AGENT VARCHAR2(1000),
STATUS_CODE NUMBER(10),
MESSAGE VARCHAR2(100),
THIRTY_SERVICE_API_URI VARCHAR2(100),
THIRTY_SERVICE_RESPONSE_TIME NUMBER(10),
CREATED_AT TIMESTAMP(6) not null,
MODIFIED_AT TIMESTAMP(6) not null
)
Where THIRTY_SERVICE_API_URI
is 3rd-party URL (ex: third-party.com/data
) and THIRTY_SERVICE_RESPONSE_TIME
is exactly response time of 3rd-party service (I'm using StopWatch
to watch response time like this post).
Here is RestTemplateInterceptor
:
@Component
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor {
final static Logger log = LoggerFactory.getLogger(RestTemplateInterceptor.class);
@Autowired
private ApiCallsTrackingRepo apiCallsTrackingRepo;
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
StopWatch stopwatch = StopWatch.createStarted();
ClientHttpResponse response = execution.execute(request, body);
stopwatch.stop();
ApiCallsTracking apiCallsTracking = ApiCallsTracking
.builder()
.requestMethod(request.getMethod().name())
.thirtyServiceAPIURI(request.getURI().toString())
.queryParams(request.getURI().getQuery())
.statusCode(response.getStatusCode().value())
.message(response.getStatusText())
.thirtyResponseTime(stopwatch.getTime(TimeUnit.MILLISECONDS))
.build();
apiCallsTrackingRepo.save(apiCallsTracking);
return response;
}
}
But I can't pass HttpServletRequest to interceptor class.
Here is my business flow:
MyController
<-> call 3rd-API via RestTemplate
<-> 3rd-API
Please help me to get request information from my API in interceptor class or guide me a trick to do this.
I want to get HttpServletRequest
information in interceptor class.
Or another word, I want to track both my API and 3rd-API.
答案1
得分: 0
为了在拦截器类中使用 RestTemplate 和 HttpServletRequest 来跟踪您的 API 和第三方 API,您可以使用 ThreadLocal 变量来存储 HttpServletRequest 信息并在拦截器中检索它。
首先,您需要在一个单独的类中创建一个 ThreadLocal 变量来存储 HttpServletRequest 信息:
public class RequestHolder {
private static final ThreadLocal<HttpServletRequest> REQUEST_THREAD_LOCAL = new ThreadLocal<>();
public static void setRequest(HttpServletRequest request) {
REQUEST_THREAD_LOCAL.set(request);
}
public static HttpServletRequest getRequest() {
return REQUEST_THREAD_LOCAL.get();
}
public static void clear() {
REQUEST_THREAD_LOCAL.remove();
}
}
您可以更新您的拦截器类以将 HttpServletRequest 存储在 RequestHolder 中:
@Component
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor
{
final static Logger log = LoggerFactory.getLogger(RestTemplateInterceptor.class);
@Autowired
private ApiCallsTrackingRepo apiCallsTrackingRepo;
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpServletRequest httpRequest = RequestHolder.getRequest();
String clientUsername = "";
String fromIp = httpRequest.getRemoteAddr();
String apiUri = httpRequest.getRequestURI();
String requestMethod = httpRequest.getMethod();
String queryParams = httpRequest.getQueryString();
String pathParams = "";
String requestPayload = "";
String userAgent = httpRequest.getHeader("User-Agent");
StopWatch stopwatch = StopWatch.createStarted();
ClientHttpResponse response = execution.execute(request, body);
stopwatch.stop();
ApiCallsTracking apiCallsTracking = ApiCallsTracking
.builder()
.clientUsername(clientUsername)
.fromIp(fromIp)
.apiUri(apiUri)
.requestMethod(requestMethod)
.queryParams(queryParams)
.pathParams(pathParams)
.requestPayload(requestPayload)
.userAgent(userAgent)
.statusCode(response.getStatusCode().value())
.message(response.getStatusText())
.thirtyServiceAPIURI(request.getURI().toString())
.thirtyServiceResponseTime(stopwatch.getTime(TimeUnit.MILLISECONDS))
.build();
apiCallsTrackingRepo.save(apiCallsTracking);
return response;
}
}
要在 RequestHolder 中填充 HttpServletRequest,您可以创建一个 HandlerInterceptor 实现,如下所示:
@Component
public class RequestInterceptor implement HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
RequestHolder.setRequest(request);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
RequestHolder.clear();
}
}
确保在您的 Spring Boot 配置中注册此拦截器。您可以通过实现 WebMvcConfigurer 接口并覆盖 addInterceptors 方法来执行此操作:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private RequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor);
}
}
通过这个设置,HttpServletRequest 信息将由 RequestInterceptor 存储在 RequestHolder 中,您可以在 RestTemplateInterceptor 中检索它,以便跟踪您的 API 和第三方 API。
英文:
To track the both your API & the 3rd party api using RestTemplate and HttpServletRequest in your interceptor class, you can make use of ThreadLocal variables to store the HttpServletRequest information and retrieve it within the interceptor.
First, you need to create a ThreadLocal variable in a separate class to store the HttpServletRequest:
public class RequestHolder {
private static final ThreadLocal<HttpServletRequest> REQUEST_THREAD_LOCAL = new ThreadLocal<>();
public static void setRequest(HttpServletRequest request) {
REQUEST_THREAD_LOCAL.set(request);
}
public static HttpServletRequest getRequest() {
return REQUEST_THREAD_LOCAL.get();
}
public static void clear() {
REQUEST_THREAD_LOCAL.remove();
}
}
you can update your interceptor class to store the HttpServletRequest in the RequestHolder:-
@Component
public class RestTemplateInterceptor implements ClientHttpRequestInterceptor
{
final static Logger log = LoggerFactory.getLogger(RestTemplateInterceptor.class);
@Autowired
private ApiCallsTrackingRepo apiCallsTrackingRepo;
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpServletRequest httpRequest = RequestHolder.getRequest();
String clientUsername = ""; String fromIp = httpRequest.getRemoteAddr();
String apiUri = httpRequest.getRequestURI();
String requestMethod = httpRequest.getMethod();
String queryParams = httpRequest.getQueryString();
String pathParams = "";
String requestPayload = "";
String userAgent = httpRequest.getHeader("User-Agent");
StopWatch stopwatch = StopWatch.createStarted();
ClientHttpResponse response = execution.execute(request, body);
stopwatch.stop();
ApiCallsTracking apiCallsTracking = ApiCallsTracking
.builder()
.clientUsername(clientUsername)
.fromIp(fromIp)
.apiUri(apiUri)
.requestMethod(requestMethod)
.queryParams(queryParams)
.pathParams(pathParams)
.requestPayload(requestPayload)
.userAgent(userAgent)
.statusCode(response.getStatusCode().value())
.message(response.getStatusText())
.thirtyServiceAPIURI(request.getURI().toString())
.thirtyServiceResponseTime(stopwatch.getTime(TimeUnit.MILLISECONDS))
.build();
apiCallsTrackingRepo.save(apiCallsTracking);
return response;
}
}
To populate the HttpServletRequest in the RequestHolder, you can create an HandlerInterceptor implementation as follows:-
@Component
public class RequestInterceptor implement HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
RequestHolder.setRequest(request);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
RequestHolder.clear();
}
}
Make sure to the register this interceptor in your Spring Boot configuration. You can do this by implementing the WebMvcConfigurer interface and overriding the addInterceptors method:-
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private RequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor);
}
}
With this setup, the HttpServletRequest information will be stored in the RequestHolder by the RequestInterceptor, and you can retrieve it in the
RestTemplateInterceptor to track both your API and the third-party API.
答案2
得分: 0
因为我正在使用ExcutorService
(通过此帖子),所以我将此代码放在任务调用者的callService
方法中,它起作用了:
tasks.add(() -> callService(servletRequest, uriBuilder, params, HttpMethod.GET));
RequestHolder.setRequest(request);
然后在restTemplate.exchange(...)
之后调用RequestUtils.clear();
。
英文:
Thanks Sandeep Rathor 's comment.
Because I'm using ExcutorService
(via this post) so I put this code in callService
method in task caller and it worked:
tasks.add(() -> callService(servletRequest, uriBuilder, params, HttpMethod.GET));
RequestHolder.setRequest(request);
then call RequestUtils.clear();
after restTemplate.exchange(...)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论