java - Wiremock 模拟代理服务器运行

标签 java spring-boot proxy webservice-client wiremock

我想为以下 e2e 场景添加一个测试:
我的应用程序正在通过内部代理服务器向外部服务发出 Web 请求,代理服务器操作请求正文,将请求转发到目标主机并返回返回的响应。
比如说
我向 external.service/an/endpoint 发帖请求(通过 my-proxy-server)正文

{
"card_number": "<proxy server pls fill the cc details>"
}
代理服务器修改请求填写cc明细,转发给external.service/an/endpoint与 body
{
"card_number": "372735466563005"
}
external.service 返回状态 OK。代理服务器不加修改地返回响应。
如何使用wiremock 测试此工作流程?我可以做 WireMock.stubFor()external.service , 但我不知道如何让wiremock 代理与我的Webclient 的代理设置一起工作。
看测试,其实是Rest Template测试,restTemplateWithWireMockAsProxyServer按预期工作,通过代理路由我的请求,但 webClientWithWireMockAsProxyServer我的 RCA 出错:
20:06:59.165 [qtp105751207-24] DEBUG wiremock.org.eclipse.jetty.server.HttpChannel - REQUEST for //localhost:58978localhost:58978 on HttpChannelOverHttp@4a71ab50{r=1,c=false,c=false/false,a=IDLE,uri=//localhost:58978localhost:58978,age=0}
CONNECT //localhost:58978localhost:58978 HTTP/1.1
Host: localhost:58978
如前所述,这些通过线模拟代理的调用是不可能的 here .但我所有的网址都像 http://localhost:<port> ,这意味着我没有进行任何 https 调用。
package com.spotnana.obt.supplier.services;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.nio.charset.StandardCharsets;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.apache.http.conn.HttpHostConnectException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.client.reactive.ReactorResourceFactory;
import org.springframework.util.SocketUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;
import reactor.netty.tcp.ProxyProvider;

@Slf4j
public class SimpleWiremockProxyServerTest {

  private final String HOST = "localhost";
  private final String MOCK_ENDPOINT = "/my/endpoint";
  private WireMockServer targetServer;
  private WireMockServer proxyServer;
  private WireMock targetWireMock;
  private WireMock proxyWireMock;
  private String targetBaseUrl;

  @Before
  public void setup() {
    final int targetPort = SocketUtils.findAvailableTcpPort();
    this.targetServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(targetPort));
    this.targetServer.start();
    this.targetWireMock = new WireMock(targetPort);
    this.targetWireMock.resetMappings();
    this.targetBaseUrl = "http://" + HOST + ":" + targetPort;

    final int proxyPort = SocketUtils.findAvailableTcpPort();
    this.proxyServer =
        new WireMockServer(
            WireMockConfiguration.wireMockConfig().port(proxyPort).enableBrowserProxying(true));
    this.proxyServer.start();
    this.proxyWireMock = new WireMock(proxyPort);
    this.proxyWireMock.resetMappings();
  }

  @After
  public void tearDown() throws HttpHostConnectException {
    this.targetWireMock.shutdown();
    this.targetServer.stop();

    try {
      this.proxyWireMock.shutdown();
      this.proxyServer.stop();
    } catch (final Exception ex) {
      log.warn("Proxy server is shutdown already");
    }
  }

  @Test
  public void restTemplateWithWireMockAsProxyServer() {
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

    Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(HOST, this.proxyServer.port()));
    requestFactory.setProxy(proxy);

    final var reqPatternBuilder =
        RequestPatternBuilder.newRequestPattern(
            RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
    final var mappingBuilder =
        WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

    reqPatternBuilder
        .withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
        .withHeader(
            HttpHeaders.ACCEPT_CHARSET,
            WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
    mappingBuilder.willReturn(
        WireMock.aResponse()
            .withStatus(HttpStatus.OK.value())
            .withBody("{ \"success\": true }")
            .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
    this.targetWireMock.register(mappingBuilder);

    ResponseEntity<String> responseEntity =
        new RestTemplate(requestFactory)
            .getForEntity(this.targetBaseUrl + MOCK_ENDPOINT, String.class);
    Assert.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
    System.out.println("responseEntity: " + responseEntity.getBody());
  }

  @Test
  public void webClientWithWireMockAsProxyServer() {
    var client = HttpClient.create()
        .tcpConfiguration(
            tcpClient ->
                tcpClient.proxy(
                    proxy -> {
                      proxy
                          .type(ProxyProvider.Proxy.HTTP)
                          .host(HOST)
                          .port(this.proxyServer.port());
                    }));
    var webClient = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(client))
        .build();

    final var reqPatternBuilder =
        RequestPatternBuilder.newRequestPattern(
            RequestMethod.GET, WireMock.urlEqualTo(MOCK_ENDPOINT));
    final var mappingBuilder =
        WireMock.get(WireMock.urlEqualTo(reqPatternBuilder.build().getUrl()));

    reqPatternBuilder
        .withHeader(HttpHeaders.ACCEPT, WireMock.containing(MediaType.APPLICATION_JSON_VALUE))
        .withHeader(
            HttpHeaders.ACCEPT_CHARSET,
            WireMock.containing(StandardCharsets.UTF_8.name().toUpperCase()));
    mappingBuilder.willReturn(
        WireMock.aResponse()
            .withStatus(HttpStatus.OK.value())
            .withBody("{ \"success\": true }")
            .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
    this.targetWireMock.register(mappingBuilder);

    var response =
        webClient.get().uri(this.targetBaseUrl + MOCK_ENDPOINT).exchange().block().bodyToMono(String.class);
    response.subscribe(x -> System.out.println("x:" + x));
  }

}
我提示错误 java.net.UnknownHostException: <proxy server>: nodename nor servname provided, or not known .有没有办法模拟wiremock代理服务器,而不是为此运行实际的服务器。我还想将验证放在代理服务器中以进行请求响应。

最佳答案

Wiremock 不支持 HTTP CONNECT method .你可以试试Hoverfly作为 Wiremock 的替代品。有a github issue如果你对细节感兴趣。

关于java - Wiremock 模拟代理服务器运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64739906/

相关文章:

java - CUPS - Cups4j - 定义页面/媒体大小

amazon-web-services - 使用 CloudFormation 禁用 AWS ECS Fargate 中的 Spring Boot Data MongoDB 可重试写入

java - CXF 客户端代理如何处理客户端内的某些响应代码

java - Java中字符串的字节数

Java String pool相关疑惑

java - Spring-boot 应用程序在执行器端口上抛出错误

docker - docker 容器的 webpack-dev-server 代理

javascript - 我可以在 Proxy 和 trap 中包装一个对象并使用 get trap 来防止 "TypeError: Cannot read property ' b' of undefined"吗?

java - 关于 ResultSet 的查询

java - 在放置、发布和删除之前进行 Spring Boot 验证