必须用URLDecoder.decode(s, "UTF-8")显式指定编码,单参数版本在Java 10+已弃用且依赖平台默认编码易导致中文解码异常;URLEncoder编码后需将+替换为%20以符合RFC 3986;Spring Boot需配置server.tomcat.uri-encoding=UTF-8防容器提前错误解码。

URLDecoder.decode() 解码中文时抛 UnsupportedEncodingException 怎么办
Java 8+ 默认用 UTF-8,但老代码或没显式指定编码时,URLDecoder.decode(String s) 会走平台默认编码(比如 Windows 上是 GBK),一解中文就崩。这不是 bug,是历史包袱。
- 必须用双参数重载:
URLDecoder.decode(s, "UTF-8"),别偷懒只传一个参数 - 如果输入可能来自不可信来源(比如旧浏览器、嵌入式设备),先检查字符串是否含
%编码,避免对已解码串重复解码——会抛IllegalArgumentException - 注意:JDK 10+ 的
URLDecoder.decode()单参数版本已被标记为@Deprecated,编译会警告
URLEncoder.encode() 编码后空格变成 + 而不是 %20,影响 API 调用
这是 RFC 3986 和早期 HTML 表单规范的差异所致。URLEncoder 是为 application/x-www-form-urlencoded 设计的,它把空格转成 +,而标准 URL 路径/查询参数里空格该是 %20。
- 路径部分(如
https://api.com/user/张三)不能用URLEncoder直接编码;得先用URLEncoder.encode("张三", "UTF-8")得到%E5%BC%A0%E4%B8%89,再手动把+替换成%20(其实空格不会出现,但其他字符如/、?也不该被编码) - 查询参数值(如
?name=张三)可以用URLEncoder.encode(),但记得之后把+换成%20才符合现代 HTTP 客户端要求(OkHttp、Spring WebClient 都期望这样) - 更稳妥的做法:用
java.net.URI构造器,它内部按 RFC 3986 处理,自动区分 scheme、path、query 各自的编码规则
Spring Boot 里 @RequestParam 接收中文参数还是乱码?别只盯 URLDecoder
乱码往往不在解码环节,而在请求进来前就被 Servlet 容器“提前解码”了。Tomcat 8.5+ 默认用 ISO-8859-1 解码 query string,遇到中文直接变 ??。
- 在
application.properties加:server.tomcat.uri-encoding=UTF-8(Spring Boot 2.3+ 可省略,但低版本必须加) - 如果用了 Nginx 做反向代理,确认它没做二次解码:
proxy_set_header X-Original-URI $request_uri;这类操作可能导致重复解码 -
@RequestParam底层确实调用了URLDecoder.decode(),但前提是容器没在你之前搞砸——所以先查request.getQueryString()原始值是否已是乱码,再决定修哪一层
替代方案:用 java.net.URLEncoder / URI 比手写 URLDecoder 更可靠
直接拼接字符串 + 手动 URLDecoder 容易漏掉边界情况,比如路径中本就存在的 %(非编码用途)、混合中英文+符号的组合。
立即学习“Java免费学习笔记(深入)”;
- 构造完整 URL 优先用
new URI(scheme, userInfo, host, port, path, query, fragment),它会对各段自动做合规编码 - 只编码某一段(比如 path 中的文件名):用
URLEncoder.encode(filename, "UTF-8").replace("+", "%20"),然后拼进URI或字符串 - 别用
String.replace("%", "%25")这种野路子预处理——会把原本合法的%20变成%2520,越修越错
真正麻烦的不是怎么编解码,而是得时刻分清:这个字符串是 raw path segment?是 form-data value?还是 query parameter value?每种语境下,哪些字符该编码、用什么规则、谁负责解码——差一层,中文就丢一次。










