使用Spring RestTemplate时如何避免[]的双重编码?
How to avoid double-encoding of [] when using Spring RestTemplate?
我有一个 Spring Boot 2.2.5 应用程序调用此 REST 端点
@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "network-ids[]", required = false) List<Integer> networkIds,
@RequestParam(name = "usages[]") Set<Usage> usages)
我的来电者确实
val url = clientUri.toString() + configuration.getUrl().getUseableProvidersForNetworks(); % 'providers/usable/search?'
val builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("usages[]", USAGES)
.queryParam("network-ids[]", networkIds);
val response =
restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
new ParameterizedTypeReference<List<Provider>>() {});
其中 USAGES
是 Set<Usage>
,networkIds
是 List<Integer>
。
RestTemplate 由
创建
RestTemplate eurekaRestTemplate() {
val requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setReadTimeout(TIMEOUT);
requestFactory.setConnectTimeout(TIMEOUT);
return new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
}
问题:[]
被双重编码为 %255B%255D
,我最终调用了
providers/usable/search?usages%255B%255D=MESSAGE_DELIVERY&network-ids%255B%255D=2145118475&network-ids%255B%255D=-1536358371
这显然行不通;服务器未命中,例如usages[]
。它适用于 []
而不是 %255B%255D
.
的 curl
我怎样才能避免这种情况?
我知道 this issue and the docs,但这并没有帮助。
我认为你不应该处理使用 []。我的意思是,没有必要使用“[]”来命名您的参数。
你为什么要这么做?
val builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("usages", USAGES)
.queryParam("network-ids", networkIds);
将完美适用于:
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "network-ids", required = false) List<Integer> networkIds,
@RequestParam(name = "usages") Set<Usage> usages)
希望对您有所帮助!
提示:在 URL 上使用 array/collection 参数时要小心,您必须考虑 URL 长度限制
解决方案是调用 UriComponentsBuilder.build(false)
指示 UriComponentsBuilder
not 编码 url:
val response = restTemplate.exchange(
builder.build(false).toUriString(),
HttpMethod.GET,
entity,
new ParameterizedTypeReference<List<Provider>>() {});
这很棘手,因为使用 Mockito/JUnit 的测试会告诉您 url 是 而非 编码,而使用 [=13= 的测试] 将显示一级编码([]
变为 %5B%5D
)。
如果您希望将编码后的 url 直接传递给 RestTemplate
,您可以通过传递 java.net.URI
来指示 RestTemplate
不对 url 进行编码而不是字符串。
这是一个使用 org.springframework.web.util.UriComponents
的示例
String url = "https://someurl/this%2Fis%2Fencoded/";
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).build(true);
ResponseEntity<String[]> file = template.exchange(uriComponents.toUri(),
HttpMethod.GET, entity,String[].class);
通过传递 UriComponentsBuilder.fromHttpUrl(url).build(true)
您实际上是让 UriComponents
知道您的 url 已经编码。
我有一个 Spring Boot 2.2.5 应用程序调用此 REST 端点
@RequestMapping(path = "/usable/search")
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "network-ids[]", required = false) List<Integer> networkIds,
@RequestParam(name = "usages[]") Set<Usage> usages)
我的来电者确实
val url = clientUri.toString() + configuration.getUrl().getUseableProvidersForNetworks(); % 'providers/usable/search?'
val builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("usages[]", USAGES)
.queryParam("network-ids[]", networkIds);
val response =
restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
new ParameterizedTypeReference<List<Provider>>() {});
其中 USAGES
是 Set<Usage>
,networkIds
是 List<Integer>
。
RestTemplate 由
创建RestTemplate eurekaRestTemplate() {
val requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setReadTimeout(TIMEOUT);
requestFactory.setConnectTimeout(TIMEOUT);
return new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory));
}
问题:[]
被双重编码为 %255B%255D
,我最终调用了
providers/usable/search?usages%255B%255D=MESSAGE_DELIVERY&network-ids%255B%255D=2145118475&network-ids%255B%255D=-1536358371
这显然行不通;服务器未命中,例如usages[]
。它适用于 []
而不是 %255B%255D
.
我怎样才能避免这种情况?
我知道 this issue and the docs,但这并没有帮助。
我认为你不应该处理使用 []。我的意思是,没有必要使用“[]”来命名您的参数。 你为什么要这么做?
val builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("usages", USAGES)
.queryParam("network-ids", networkIds);
将完美适用于:
public List<Provider> findUsable(
@RequestParam(name = "country-id", required = false) Integer countryId,
@RequestParam(name = "network-ids", required = false) List<Integer> networkIds,
@RequestParam(name = "usages") Set<Usage> usages)
希望对您有所帮助!
提示:在 URL 上使用 array/collection 参数时要小心,您必须考虑 URL 长度限制
解决方案是调用 UriComponentsBuilder.build(false)
指示 UriComponentsBuilder
not 编码 url:
val response = restTemplate.exchange(
builder.build(false).toUriString(),
HttpMethod.GET,
entity,
new ParameterizedTypeReference<List<Provider>>() {});
这很棘手,因为使用 Mockito/JUnit 的测试会告诉您 url 是 而非 编码,而使用 [=13= 的测试] 将显示一级编码([]
变为 %5B%5D
)。
如果您希望将编码后的 url 直接传递给 RestTemplate
,您可以通过传递 java.net.URI
来指示 RestTemplate
不对 url 进行编码而不是字符串。
这是一个使用 org.springframework.web.util.UriComponents
String url = "https://someurl/this%2Fis%2Fencoded/";
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).build(true);
ResponseEntity<String[]> file = template.exchange(uriComponents.toUri(),
HttpMethod.GET, entity,String[].class);
通过传递 UriComponentsBuilder.fromHttpUrl(url).build(true)
您实际上是让 UriComponents
知道您的 url 已经编码。