2

我的 Spring Boot API 正在使用 WebClient 使用第三方 API

演示API控制器

@RestController
public class DemoAPIController
{
  @Autowired
  DemoService demoService;

  @GetMapping("/mytest")
  public Mono<UserType> getUserType()
  {
    return demoService.getUserType();
  }
}

演示服务.java

@Component
public class DemoService
{
  @Value("${base.url}")
  private String baseUrl;

  public Mono<UserType> getUserType()
  {
    System.out.println("baseUrl:" + baseUrl);
    WebClient webClient = WebClient.builder().baseUrl(baseUrl)
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .defaultHeader("apikey", "test").build();

    Mono<UserType> testResult = webClient.get()
        .uri("/valic/valic-security-data-api/v1/utility/users/ID873366777/usertype?appName=EAO").retrieve()
        .bodyToMono(UserType.class);
    testResult.subscribe(value -> System.out.println(value.getUserType()));
    return testResult;
  }
}

我已经使用 MockWebServer 模拟了第三方 API。当我尝试使用 mockMvc.perform(...) 测试 API 时。我的断言按预期工作。但是在关闭 MockWebServer 时,我收到以下异常

2019-11-29 16:02:43.308  INFO 13048 --- [127.0.0.1:53970] okhttp3.mockwebserver.MockWebServer      : MockWebServer[443] received request: GET /valic/valic-security-data-api/v1/utility/users/ID873366777/usertype?appName=EAO HTTP/1.1 and responded: HTTP/1.1 200 OK
2019-11-29 16:03:18.362  INFO 13048 --- [ckWebServer 443] okhttp3.mockwebserver.MockWebServer      : MockWebServer[443] done accepting connections: socket closed
2019-11-29 16:03:18.385  WARN 13048 --- [ctor-http-nio-1] r.netty.http.client.HttpClientConnect    : [id: 0x186c45c1, L:0.0.0.0/0.0.0.0:53970 ! R:localhost/127.0.0.1:443] The connection observed an error

reactor.netty.http.client.PrematureCloseException: Connection prematurely closed BEFORE response

2019-11-29 16:03:18.389  INFO 13048 --- [127.0.0.1:53970] okhttp3.mockwebserver.MockWebServer      : MockWebServer[443] connection from /127.0.0.1 failed: java.net.SocketException: Socket closed
2019-11-29 16:03:20.509  INFO 13048 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

我的测试用例

@ExtendWith(SpringExtension.class)
@WebAppConfiguration()
@ContextConfiguration(classes = WebclientApplication.class)
@SpringBootTest
public class EmployeeServiceMockWebServerTest
{
  public static MockWebServer mockWebServer;
  private ObjectMapper MAPPER = new ObjectMapper();

  public MockMvc mockMvc;

  public MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
      MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

  public MediaType contentTypeURLEncoded = new MediaType(MediaType.APPLICATION_FORM_URLENCODED.getType(),
      MediaType.APPLICATION_FORM_URLENCODED.getSubtype(), Charset.forName("utf8"));

  @Autowired
  private WebApplicationContext webApplicationContext;

  @BeforeAll
  static void setUp() throws IOException
  {
    mockWebServer = new MockWebServer();
    mockWebServer.start(443);
  }

  @AfterAll
  static void tearDown() throws IOException
  {
    mockWebServer.shutdown();
  }

  @BeforeEach
  void initialize()
  {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    System.out.println("Hostname:" + mockWebServer.getHostName());
    System.out.println("Port:" + mockWebServer.getPort());
  }

  @Test
  void getEmployeeById() throws Exception
  {
    UserType userType = new UserType();
    userType.setUserType("PAR-Mock");
    ServiceMessage serviceMessage = new ServiceMessage();
    serviceMessage.setCode("200");
    serviceMessage.setType("OK");
    serviceMessage.setDescription("From Mock");
    userType.setServiceMessage(serviceMessage);

    mockWebServer.enqueue(
        new MockResponse().setBody(MAPPER.writeValueAsString(userType)).addHeader("Content-Type", "application/json"));

    mockMvc.perform(get("/mytest").contentType(contentType)).andExpect(status().isOk());

    RecordedRequest recordedRequest = mockWebServer.takeRequest();
    assertEquals("GET", recordedRequest.getMethod());
    assertEquals("/logic/logic-security-data-api/v1/utility/users/ID873366777/usertype?appName=EAO",
        recordedRequest.getPath());
  }
}

我尝试了其他启动溢出帖子中提到的所有解决方案,但仍然遇到相同的错误。任何帮助表示赞赏。

4

1 回答 1

2

我通过评论以下行解决了这个问题。

testResult.subscribe(value -> System.out.println(value.getUserType()));

我使用以下代码创建了 WebClient 对象以获取额外的日志记录

WebClient webClient = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(HttpClient.newConnection().compress(true).wiretap(true)))
    .baseUrl(baseUrl).defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .defaultHeader("apikey", "somekey").build();

我能够看到两个请求。然后在发表评论后,一切都按预期工作。

于 2019-12-03T21:59:50.270 回答