RestTemplate exchange方法URI双重编码致404问题求助
我来帮你解决这个问题!你遇到的其实是URL二次编码的问题——你手动把空格转成了%20,但RestTemplate默认会对整个URI再次编码,导致%被转成%25,于是%20就变成了%2520,这自然会让XWiki找不到对应的资源。
核心原因
RestTemplate的exchange方法如果接收的是字符串类型的URL,会默认把它当作未编码的原始字符串进行编码处理。而你已经提前将空格转成了%20,这就导致%字符被二次编码为%25,最终出现%2520的错误格式。
解决方案1:让UriComponentsBuilder自动处理编码(推荐)
不要提前手动编码URL,而是使用原始的带空格的路径,让UriComponentsBuilder帮你完成编码工作,从根源避免二次编码:
public static void main(String[] args) throws IOException, URISyntaxException { // 使用原始空格的路径,不要手动转%20 String baseUrl = "http://swininducasa02.ptx.fr.sopra:8080/xwiki-enterprise-web-8.4.5/rest/wikis/xwiki/spaces/Main/spaces/PIC/spaces/Serveur de virtualisation/spaces/Serveur de Marcoussis/spaces/choix/spaces/SGBFV/pages/WebHome"; String plainCreds = "user:passwd"; byte[] plainCredsBytes = plainCreds.getBytes(); byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); String base64Creds = new String(base64CredsBytes); HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + base64Creds); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); // 构建正确编码的URI,自动处理空格转%20 URI uri = UriComponentsBuilder.fromHttpUrl(baseUrl) .queryParam("media", "json") .build() .toUri(); RestTemplate restTemplate = new RestTemplate(); System.out.println("Begin /GET request!"); HttpEntity<String> request = new HttpEntity<>(headers); ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, request, String.class); Map<String, String> map = new ObjectMapper().readValue(response.getBody(), Map.class); System.out.println(map.get("content")); }
解决方案2:直接使用已编码的URI对象
如果你必须使用已经手动编码好的URL字符串,可以直接创建URI对象传入exchange方法——当传入URI对象时,RestTemplate会跳过编码步骤:
public static void main(String[] args) throws IOException, URISyntaxException { String link = "http://swininducasa02.ptx.fr.sopra:8080/xwiki-enterprise-web-8.4.5/rest/wikis/xwiki/spaces/Main/spaces/PIC/spaces/Serveur%20de%20virtualisation/spaces/Serveur%20de%20Marcoussis/spaces/choix/spaces/SGBFV/pages/WebHome"; String plainCreds = "user:passwd"; byte[] plainCredsBytes = plainCreds.getBytes(); byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes); String base64Creds = new String(base64CredsBytes); HttpHeaders headers = new HttpHeaders(); headers.add("Authorization", "Basic " + base64Creds); headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); // 直接创建URI对象,避免二次编码 URI uri = new URI(link + "?media=json"); RestTemplate restTemplate = new RestTemplate(); System.out.println("Begin /GET request!"); HttpEntity<String> request = new HttpEntity<>(headers); ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, request, String.class); Map<String, String> map = new ObjectMapper().readValue(response.getBody(), Map.class); System.out.println(map.get("content")); }
为什么你之前的尝试没成功?
你之前用UriComponentsBuilder.fromPath(link).build(true)时,link已经是编码后的字符串,fromPath会把它当作原始路径处理,依然会对%字符进行编码,所以问题没有解决。正确的做法要么用原始路径让工具自动编码,要么直接用URI对象跳过编码环节。
内容的提问来源于stack exchange,提问作者kadar
相关产品推荐
相关产品推荐

