问题一:请求url中包含%被转义为%25
resteTemplate中url如果带%,被被转义成%25,无法正确的访问资源
例如: http://localhost:8080/aa?param=sdlfjdl&name=%123
会被转为:http://localhost:8080/aa?param=sdlfjdl&name=%25123
问题代码
String url = "http://localhost:8080/aa?param=sdlfjdl&name=%123";
try{
restTemplate.getForEntity(url, String.class);
}catch (Exception e){
}
问题原因
restTemplate的exchange方法,若参数url是String类型在发送请求之前会先将String类型的url转为URI类型的url,在这个过程中会对url进行转义,如下面的restTemplate的源码中的方法:
@Nullable
public <T> T execute(String url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor, Map<String, ?> uriVariables) throws RestClientException {
URI expanded = this.getUriTemplateHandler().expand(url, uriVariables);
return this.doExecute(expanded, method, requestCallback, responseExtractor);
}
因此这里直接采用restTemplate传参为URI的方法,将url的字符串编码转成URI就可以了:
@Nullable
public <T> T execute(URI url, HttpMethod method, @Nullable RequestCallback requestCallback, @Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
return this.doExecute(url, method, requestCallback, responseExtractor);
}
问题解决
注意:若get请求参数中包含特殊字符&,则下面的这个解决方法还是有问题的,要想解决请求参数包含&可以参考下面问题二中的解决方法
String url = "http://localhost:8080/aa?param=sdlfjdl&name=%123";
try{
URI uri = URI.create(url);
restTemplate.getForEntity(uri, String.class);
}catch (Exception e){
}
问题二:RestTemplate发送get请求,请求参数中包含特殊字符&
解决方法
所有发送get请求,请求中包含特殊字符,如% & + = 空格 等都可以使用以下解决方法,目前没发现异常
public String get(String url, List<NameValuePair> params, List<NameValuePair> headerParams){
String response = "";
log.info("请求地址:{},请求头参数:{},请求参数:{}",url,headerParams,params);
try {
HttpHeaders headers = new HttpHeaders();
if(!CollectionUtils.isEmpty(headerParams)){
headerParams.forEach(p ->
headers.add(p.getName(),p.getValue())
);
}
HttpEntity<String> httpEntity = new HttpEntity<>(null,headers);
URI uri = URI.create(url);
if(!CollectionUtils.isEmpty(params)){
String param = URLEncodedUtils.format(params, StandardCharsets.UTF_8);
uri = URI.create(url+"?"+param);
}
//url中若带了参数,不要使用String url的方式传入,里面的+ = % &等符号会被转义或替换掉,所以传入URI对象
response = restTemplate.exchange(uri, HttpMethod.GET, httpEntity , String.class).getBody();
}catch (Exception e){
log.error("请求:"+url+"时发生未知异常"+e.getMessage(),e);
}
return response;
}
调用:
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("name", "tom"));
params.add(new BasicNameValuePair("age", "&%24"));
String response = get("http://localhost/8080/aa",params,null);
URL中的特殊字符
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了。编码的格式为:%加字符的ASCII码,即一个百分号%,后面跟对应字符的ASCII(16进制)码值。对于ASCII码不了解的同学,可以参考ASCII码 http://c.biancheng.net/c/ascii/,例如 空格的编码值是"%20"。
下表中列出了一些URL特殊符号及编码
符号 | 含义 | 转义后 |
---|---|---|
+ | URL 中+号表示空格 | %2B |
空格 | URL中的空格可以用+号或者编码 | %20 |
/ | 分隔目录和子目录 | %2F |
? | 分隔实际的URL和参数 | %3F |
% | 指定特殊字符 | %25 |
# | 表示书签 | %23 |
& | URL 中指定的参数间的分隔符 | %26 |
= | URL 中指定参数的值 | %3D |