gpt4 book ai didi

java - 如何让 RestTemplate 使用 UriComponents 和 EncodingMode.VALUES_ONLY 对所有字符进行编码?

转载 作者:行者123 更新时间:2023-12-02 11:02:16 36 4
gpt4 key购买 nike

我想要我的 REST 客户端,使用 Spring Web 的 RestTemplate ,对 URL 参数中的所有特殊字符进行 % 编码,而不仅仅是非法字符。 Spring Web's documentation指出可以通过配置 DefaultUriBuilderFactory 来更改编码方法由 RestTemplate 使用与 setEncodingMode(EncodingMode.VALUES_ONLY) :

String baseUrl = "http://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.VALUES_ONLY);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);

这个should “将 UriUtils.encode(String, Charset) 应用于每个 URI 变量值”,这反过来将“按照 RFC 3986 中的定义,对 URI 中任何位置的所有非法字符或具有任何保留含义的字符进行编码”。

我编写了以下测试用例来尝试演示更改为 EncodingMode.VALUES_ONLY没有达到预期的效果。 (使用依赖项 org.springframework.boot:spring-boot-starter:2.0.3.RELEASEorg.springframework:spring-web:5.0.7.RELEASEorg.springframework.boot:spring-boot-starter-test:2.0.3.RELEASE 执行它)

package com.example.demo.encoding;

import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;

import java.nio.charset.StandardCharsets;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;

@RunWith(SpringRunner.class)
@RestClientTest(DemoClient.class)
public class EncodingTest {
@Autowired private MockRestServiceServer mockServer;
@Autowired private DemoClient client;

@Test
public void encodeAllCharactersInParameter() {
mockServer.expect(requestTo(encodedQueryUrl("https://host", "+:/")))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess());
client.request("https://host", "+:/");
mockServer.verify();
}

private String encodedQueryUrl(final String baseUrl, final String parameter) {
return String.format("%s?parameter=%s", baseUrl,
UriUtils.encode(parameter, StandardCharsets.UTF_8));
}
}

@Component
class DemoClient {
private final RestTemplate restTemplate;

public DemoClient(RestTemplateBuilder restTemplateBuilder) {
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
factory.setEncodingMode(EncodingMode.VALUES_ONLY);
restTemplateBuilder.uriTemplateHandler(factory);
this.restTemplate = restTemplateBuilder.build();
}

public Object request(final String url, final String parameter) {
UriComponents queryUrl = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("parameter", parameter).build().encode();
return restTemplate.getForObject(queryUrl.toUri(), Object.class);
}
}

此测试失败,并显示 java.lang.AssertionError: Request URI expected:<https://host?parameter=%2B%3A%2F> but was:<https://host?parameter=+:/> 。那么我做错了什么?这是 Spring Framework 中的错误还是 MockRestServiceServer在验证期望之前解码 URL?

最佳答案

示例中的两个问题:

第一,请求方法在外部准备并编码 java.net.URI,因此 RestTemplate 不是准备它的人。您需要传递一个包含 URI 变量的 URI 模板,以便 RestTemplate 有机会准备 URI 并进行编码。例如:

public Object request(final String url, final String parameter) {
String urlString = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("parameter", "{param}")
.build()
.toUriString();
return restTemplate.getForObject(urlString, Object.class, parameter);
}

或者只是让请求获取 URI 模板字符串:

public Object request(final String url) {
return restTemplate.getForObject(url, Object.class, parameter);
}

// then invoke like this...
request("https://host?parameter={param}");

二,RestTemplateBuilder#uriTemplateHandler 返回一个新实例,因此您需要使用它来使配置更改生效:

DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory();
factory.setEncodingMode(EncodingMode.VALUES_ONLY);
restTemplateBuilder = restTemplateBuilder.uriTemplateHandler(factory); // <<<< see here
this.restTemplate = restTemplateBuilder.build();

经过上述更改后,它可以按预期工作。

请注意https://jira.spring.io/browse/SPR-17039使用 UriComponentsBuilder 可以更轻松地实现相同的效果,因此请检查那里的更新。

关于java - 如何让 RestTemplate 使用 UriComponents 和 EncodingMode.VALUES_ONLY 对所有字符进行编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51241321/

36 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com