记录客户端请求拦截器和HttpServletRequest(或HandlerInterceptor)的日志。

huangapple go评论58阅读模式
英文:

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&lt;HttpServletRequest&gt; REQUEST_THREAD_LOCAL = new ThreadLocal&lt;&gt;();

    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 = &quot;&quot;;         String fromIp = httpRequest.getRemoteAddr();
        String apiUri = httpRequest.getRequestURI();
        String requestMethod = httpRequest.getMethod();
        String queryParams = httpRequest.getQueryString();
        String pathParams = &quot;&quot;;
        String requestPayload = &quot;&quot;; 
        String userAgent = httpRequest.getHeader(&quot;User-Agent&quot;);

        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(() -&gt; callService(servletRequest, uriBuilder, params, HttpMethod.GET));
RequestHolder.setRequest(request); 

then call RequestUtils.clear(); after restTemplate.exchange(...)

huangapple
  • 本文由 发表于 2023年7月3日 12:44:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76601886.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定