Spring RestTemplate GET请求返回结果与curl/浏览器不一致求助
看起来你遇到的问题很典型——同一个URL,用RestTemplate请求返回空结果,但curl或浏览器却能拿到正确数据。我来帮你拆解可能的原因和解决方案:
1. 排查双重URL编码问题
你当前手动用UriUtils.encode()处理了keywords参数,然后调用build(true)告诉UriComponentsBuilder“参数已经编码过了”。但这里有个潜在风险:如果RestTemplate在发送请求时又对URL做了一次编码(虽然理论上build(true)会避免这个),就会导致服务器收到的关键词是双重编码后的内容,自然返回空结果。
修复方案:去掉手动编码,让UriComponentsBuilder自动处理参数编码——它的queryParam()方法本身就会按照标准URL编码规则处理参数:
UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(URL + "search/all") .queryParam("keywords", person) .build(); ResponseEntity<String> responseEntity = restTemplate.getForEntity(uriComponents.toUriString(), String.class);
生成的URL应该和你之前手动编码的完全一致,但避免了双重编码的隐患。
2. 对比请求头差异
curl和浏览器的默认请求头,和RestTemplate的默认请求头可能不一样。很多服务器会根据Accept、User-Agent等头信息返回不同的内容(比如有的服务器对非浏览器请求返回空或简化结果)。
验证方法:给RestTemplate添加请求拦截器,打印实际发送的请求头,和curl的请求头对比:
restTemplate.getInterceptors().add((request, body, execution) -> { System.out.println("Request Headers: " + request.getHeaders()); return execution.execute(request, body); });
然后执行curl命令时加上-v参数查看请求头:
curl -v https://example.com/api/v3/search/all?keywords=%C3%89tienne%20Racicot
修复方案:如果发现头信息不一致,手动设置RestTemplate的请求头,模拟curl的请求:
HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "*/*"); // 匹配curl的默认Accept头 headers.set("User-Agent", "curl/7.68.0"); // 换成你的curl版本 HttpEntity<Void> requestEntity = new HttpEntity<>(headers); UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(URL + "search/all") .queryParam("keywords", person) .build(); ResponseEntity<String> responseEntity = restTemplate.exchange( uriComponents.toUri(), HttpMethod.GET, requestEntity, String.class );
3. 改用toUri()而非toUriString()
有时候toUriString()会在URL拼接时引入编码问题,改用toUri()直接传递URI对象给RestTemplate,能避免字符串处理带来的意外:
ResponseEntity<String> responseEntity = restTemplate.getForEntity(uriComponents.toUri(), String.class);
4. 检查是否存在重定向或Cookie问题
如果服务器需要特定的Cookie(比如会话标识)才能返回正确结果,curl或浏览器可能自动保存了Cookie,但RestTemplate默认不会。这种情况下,你需要在RestTemplate中配置Cookie存储,或者手动添加Cookie头。
先试试上面的前三个方案,大概率能解决问题——我遇到过好几次类似的情况,都是请求头或编码的问题导致的。
内容的提问来源于stack exchange,提问作者user3221287

