RestTemplate 的自动encoding URI
场景
RestTemplate 传递一个参数 properties={json}, 为一个json对象。
由于 resttemplate 使用 在处理Url时候会 对 参数进行expand。也就是如下规则:
http://localhost/app? properties={"a":"b"}
RestTemplate 是不支持直接调用这样的url string 的。 比如getForObject(url,String.class)
原因: 就是因为 resttemplate 多了异步 expand 的过程,他会把 url String
expand 成 URI。
于是尝试使用 encoding {}在传输数据
String props = mapper.writeValueAsString(ImmutableMap.of(key, value));
Map<String, Object> params = ImmutableMap.of(
"label", label,
"properties", URLEncoder.encode(props,"UTF-8")
);
String content = RestClient.get(URL_PREFIX + GRAPH_VERTEX, params)
.getBody();
public static ResponseEntity<String> get(String uri, Map<String,Object> params)
{
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(uri);
params.entrySet().stream().forEach(o -> builder.queryParam(o.getKey(),o.getValue()));
return get(builder.build().toString());
}
properties", URLEncoder.encode(props,"UTF-8")
builder.build().toString() 出来的结果是:
http://127.0.0.1:8080/graphs/hugegraph/graph/vertices?label=person&properties=%7B%22name%22%3A%22peter%22%7D
坑在这里,此时如果 使用
return restTemplate.getForEntity(url,clazz);
会造成程序错过,Server 无法解析到 真确的 propreties,
因为 getForEntity(String,Class) 这一类方法,默认你是传递一个没有expand 的urlstring 过来的。
所以他还会做一个expand,expand 包括了 填充参数 + url encoding。
我们前面已经使用了 UriComponentsBuilder,这个也会encoding, 这就造成了, encoding了两次
服务器端只会解析一次, 所有就拿不到解析好的 properties 字段。
正确的做法:
如果 已经使用 UriComponentsBuilder builder 做了 expand 和 encoding。只需要
restTemplate.getForEntity(URI.create(uri),clazz);
这样直接使用 URI,不会在expand