【问题标题】:Springboot external api call request and response capture in database数据库中的Spring Boot外部api调用请求和响应捕获
【发布时间】:2020-02-01 04:47:13
【问题描述】:

从我的后端应用程序(springboot,java8)我将进行多个外部 api 调用。我需要将所有请求和响应数据(包括标头、请求和响应正文)记录到数据库(MongoDB)中。

以下是我的示例代码,这是我尝试捕获每个外部 api 调用的请求和响应的方式。在异常情况下,我会将状态存储为“失败”。

在我的项目中,将在新的第 3 方 api 集成中添加多个模块,因此在每个不同的外部 api 调用的每个模块中,我必须像这样捕获所有请求和响应。我对以下方法不满意。请提出解决此问题的最佳方法。

示例服务层方法

public ResponseDTOFromExternalApi externalApiCallServiceMethod(String clientId, RequestDTO requestDTO) {

        ExternalApiCallRequestObj externalApiCallRequestObj = prepareExternalApiRequestObjFromRequestDTO(requestDTO);
        ApiCall apiCall = ApiCall.builder()
                .clientId(clientId)
                .status("SUBMITTED")
                .requestPayload(externalApiCallRequestObj)
                .build();

        apiCall = apiCallRepository.save(apiCall);

        ExternalApiCallReponseObj externalApiCallReponseObj = externalApiCallService.callExternalApi1(externalApiCallRequestObj);

        apiCall = apiCallRepository.findById(apiCall.getId());

        apiCall.setResponsePayload(externalApiCallReponseObj);
        apiCall.setStatus("COMPLETED");

        apiCallRepository.save(apiCall);

        return toDTO(externalApiCallReponseObj);
}

api 调用的示例域

@Document("api_calls")
@Builder
@Data
public class ApiCall {

    @Id
    private String id;

    private String clientId;

    private String status;

    private Object requestPayload;

    private Object responsePayload;

}

【问题讨论】:

    标签: java spring-boot design-patterns microservices software-design


    【解决方案1】:

    Spring 的 WebClient 已经能够通过添加交换过滤器来记录所有请求和响应数据。

    通过将它用于您的网络请求,剩下要做的就是将此信息写入您的 mongodb。

    这里是关于记录请求和响应的教程: https://www.baeldung.com/spring-log-webclient-calls

    干杯

    【讨论】:

      【解决方案2】:

      您可以使用 Spring AOP 来解决这个横切问题。

      假设ExternalApiCallService 是一个spring managed bean,下面的代码将拦截所有callExternalApi1() 并可以将其记录到数据库中。

      @Component
      @Aspect
      public class ExternalCallLoggerAspect {
      
          @Autowired
          ApiCallRepository apiCallRepository;
      
          @Pointcut("execution(* *..ExternalApiCallService.callExternalApi1(..))")
          public void externalApiCallService(){}
      
      
          @Around("externalApiCallService() && args(request)")
          public ExternalApiCallReponseObj logCalls(ProceedingJoinPoint pjp,ExternalApiCallRequestObj request){
      
            Object result=null;
            String status = "COMPLETED";
            ExternalApiCallReponseObj response = null;
      
              // Build the apiCall from request 
              ApiCall apiCall = ApiCall.builder()
                      .clientId(clientId)
                      .status("SUBMITTED")
                      .requestPayload(request)
                      .build();
      
              //save the same to db
              apiCall = apiCallRepository.save(apiCall);
      
              // Proceed to call the external Api and get the result
              try {
                 result = pjp.proceed();
              } catch (Throwable e) {
                 status = "FAILED";
              }
      
              //Update the response           
              apiCall = apiCallRepository.findById(apiCall.getId());            
              apiCall.setStatus(status);
              apiCallRepository.save(apiCall);
      
              if(result != null) {
                response = (ExternalApiCallReponseObj)result;
                apiCall.setResponsePayload(response);
              }
      
              //continue with response
              return response;
          }
      
      }
      

      注意

      1.名称ExternalApiCallReponseObj有错别字

      2. 方面代码经过验证可以正常工作,并且稍后包含未经测试的逻辑。请进行必要的更正

      理想情况下,应该将原始方法精简到此

      public ResponseDTOFromExternalApi externalApiCallServiceMethod(String clientId, RequestDTO requestDTO) {
      
             return toDTO(externalApiCallService.callExternalApi1(prepareExternalApiRequestObjFromRequestDTO(requestDTO)));
      }
      

      更多关于 Spring AOP here


      更新:再想一想,如果所有外部 api 调用都通过一个方法,比如ExternalApiCallService.callExternalApi1(),那么这个日志记录逻辑可以移到那个共同点,不是吗?

      【讨论】:

        猜你喜欢
        • 2021-04-07
        • 2020-05-06
        • 1970-01-01
        • 2019-11-06
        • 1970-01-01
        • 1970-01-01
        • 2017-03-07
        • 1970-01-01
        • 2019-09-01
        相关资源
        最近更新 更多