【问题标题】:webflux constructs incorrect URL valuewebflux 构造错误的 URL 值
【发布时间】:2020-12-07 05:18:09
【问题描述】:

我想使用 Spring Webflux 发出 POST 请求。我试过这个:

Web 客户端构建:

public RestClient(String gatewayUrl, String token, String username, String password, SslContext sslContext) {
        this.token = token;
        this.gatewayUrl = gatewayUrl;
        WebClient.Builder builder = WebClient.builder().baseUrl(gatewayUrl);
        if (sslContext != null) {
            HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec.sslContext(sslContext));
            ClientHttpConnector httpConnector = new ReactorClientHttpConnector(httpClient);
            builder.clientConnector(httpConnector);
        }
        if (username != null && password != null) {
            builder.filter(basicAuthentication(username, password));
        }
        client = builder.build();
    }


......

public class RestClientBuilder {
    private String token;
    private String username;
    private String password;
    private URL gatewayUrl;
    private SslContextBuilder sslContextBuilder;

    public static RestClientBuilder builder() {
        return new RestClientBuilder();
    }

    public RestClientBuilder token(String token) {
        this.token = validateAndTrim(token, "Token");
        return this;
    }

    public RestClientBuilder usernamePassword(String username, String password) {
        this.username = validateAndTrim(username, "Username");
        this.password = validateAndTrim(password, "Password");
        return this;
    }

    private String validateAndTrim(String value, final String parameter) {
        if (value == null || value.trim().isEmpty()) {
            throw new IllegalArgumentException(parameter + " is empty");
        }
        return value.trim();
    }

    public RestClientBuilder gatewayUrl(String gatewayUrl) {
        String urlSt = validateAndTrim(gatewayUrl, "Gateway URL");
        try {
            this.gatewayUrl = new URL(urlSt);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("Malformed URL: " + urlSt, e);
        }
        return this;
    }

    public RestClientBuilder truststore(File truststoreFile) {
        getSslContextBuilder().trustManager(truststoreFile);
        return this;
    }

    public RestClientBuilder sslCertificate(File keyCertChainFile, File keyFile, String keyPassword) {
        getSslContextBuilder().keyManager(keyCertChainFile, keyFile, keyPassword);
        return this;
    }

    public RestClient build() throws SSLException {
        SslContext sslContext = sslContextBuilder != null ? sslContextBuilder.build() : null;
        return new RestClient(gatewayUrl.toString(), token, username, password, sslContext);
    }

    private SslContextBuilder getSslContextBuilder() {
        if (sslContextBuilder == null) {
            sslContextBuilder = SslContextBuilder.forClient();
        }
        return sslContextBuilder;
    }

}

测试成功:

        client.post()
            .uri("https://test.oppwa.com/v1/checkouts?entityId=1234567&amount=92.00&currency=GBP&paymentType=DB")
            .header(HttpHeaders.USER_AGENT, "Mozilla/5.0")
            .header(HttpHeaders.AUTHORIZATION, "Bearer 11111111")
            .accept(MediaType.APPLICATION_JSON)
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .retrieve()
            .bodyToMono(SaleResponse.class);

请求失败:

MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("entityId", "1234567");
        map.add("amount", "92.00");
        map.add("currency", "GBP");
        map.add("paymentType", "DB");

            client.post()
                .uri(uriBuilder -> uriBuilder.path("https://test.oppwa.com/v1/checkouts")
                        .queryParams(map)
                        .build())
                .header(HttpHeaders.USER_AGENT, "Mozilla/5.0")
                .header(HttpHeaders.AUTHORIZATION, "Bearer 11111111")
                .accept(MediaType.APPLICATION_JSON)
                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                .retrieve()
                .bodyToMono(SaleResponse.class);

由于某种原因,Webflux 构造了这个值:

.WebClientResponseException$NotFound: 404 Not Found from POST https://test.oppwa.com/v1/checkoutshttps:/test.oppwa.com/v1/checkouts?entityId=1234567&amount=92.00&currency=GBP&paymentType=DB

你知道为什么 url 链接重复了 2 次吗?我该如何解决这个问题?

【问题讨论】:

  • 你从哪里得到uriBuilder(你知道在第一个sn-p中你完全放弃了使用它的结果吗?)?
  • uriBuilder 是一个 Java Lambda 表达式。
  • 客户端是否设置了基本路径?
  • 我犯了一个错误。帖子已更新。
  • 我没有基本路径的配置。

标签: java spring spring-boot spring-webflux


【解决方案1】:

您正在构建一个带有网关基础 url 的 RestClient:

WebClient.Builder builder = WebClient.builder().baseUrl(gatewayUrl);

在 spring 文档中,您可以阅读 baseUrl 的以下内容:

DefaultUriBuilderFactory 用于为具有给定基本 URL 的每个请求准备 URL,除非给定 URL 的 URL 请求是绝对的,在这种情况下基本 URL 将被忽略。

WebClient.builder#baseUrl

在你的例子中:

// Here you are supplying a an absolute url, which means base url is ignored
client.post()
      .uri("https://test.oppwa.com/v1/checkouts?entityId=1234567&amount=92.00&currency=GBP&paymentType=DB"

在你的另一个例子中:

client.post()
      // Here you are supplying only a path
      .uri(uriBuilder -> uriBuilder.path("https://test.oppwa.com/v1/checkouts")
                            .queryParams(map)
                            .build())

对于路径的文档,它说:

附加到此构建器的路径。 给定值按原样附加,除了清除重复项之外,不检查斜线。

如果您需要更改基本 url,我建议您将 url 放在属性文件中,并在启动时加载它们。因此,根据环境(开发、测试、产品),您可以使用自己的配置加载不同的配置文件并将其设置为 baseUrl。然后使用 UrlBuilder 在顶部附加不同的路径。

UriBuilder#Path

【讨论】:

    猜你喜欢
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 2017-07-31
    相关资源
    最近更新 更多