Spring Boot重定向含德语变音字符URL的UTF-8编码异常及解决
问题背景
2024年仍存在UTF-8编码相关问题,测试项目仅包含两个核心类(其余为Spring Initializr生成的模板代码)。核心逻辑如下:
@GetMapping("/hallo") public String hallo() { return "redirect:/hallöchen"; } @ResponseBody @GetMapping("/hallöchen") public String helloWithUmlaut() { return "Hallöchen"; }
使用默认Tomcat引擎运行时,访问/hallo会返回400状态码,错误信息:
java.lang.IllegalArgumentException: Invalid character found in the request target [/hall0xc30xb6chen ]. The valid characters are defined in RFC 7230 and RFC 3986
该错误在CoyoteAdapter类的convertURI方法第1068行抛出,注释明确提到本不应发生:
// Should never happen as B2CConverter should replace // problematic characters request.getResponse().sendError(HttpServletResponse.SC_BAD_REQUEST);
但直接访问/hallöchen时一切正常。
问题原因
直接访问含变音字符的URL时,浏览器会自动对非ASCII字符(如ö)进行URL编码,转换为符合RFC规范的%C3%B6,Tomcat能正常处理。
但Spring Boot处理redirect:前缀的返回值时,默认不会自动对路径中的非ASCII字符做URL编码,直接将未编码的/hallöchen作为重定向目标发送给Tomcat。Tomcat的URL校验逻辑识别到未编码的特殊字符后,触发RFC规范校验抛出400错误——尽管Tomcat的B2CConverter理论上会替换问题字符,但未编码的URL已经触发了前置校验,导致错误提前抛出。
最简标准解决方法
使用Spring官方提供的UriComponentsBuilder工具类构建编码后的重定向URL,它会自动处理非ASCII字符的URL编码,是符合规范的最优解法:
import org.springframework.web.util.UriComponentsBuilder; @GetMapping("/hallo") public String hallo() { // 自动对路径中的非ASCII字符进行URL编码 String encodedRedirectUrl = UriComponentsBuilder.fromPath("/hallöchen").build().toUriString(); return "redirect:" + encodedRedirectUrl; }
也可以通过返回RedirectView实现,效果一致:
import org.springframework.web.servlet.view.RedirectView; import org.springframework.web.util.UriComponentsBuilder; @GetMapping("/hallo") public RedirectView hallo() { RedirectView redirectView = new RedirectView(); redirectView.setUrl(UriComponentsBuilder.fromPath("/hallöchen").build().toUriString()); return redirectView; }
UriComponentsBuilder会将ö编码为%C3%B6,生成符合RFC规范的重定向目标URL,Tomcat能正常处理,不会再抛出400错误。
内容的提问来源于stack exchange,提问作者Janning Vygen

