urldecoder.decode() 解码中文必须用双参数指定 utf-8,单参数已弃用且默认 iso-8859-1 导致乱码;urlencoder 只适用于 query value 编码,不可用于 path;spring 需配置 server.tomcat.uri-encoding=utf-8;推荐 java 11+ 使用 uri 或 uricomponentsbuilder。

URLDecoder.decode() 解码中文时抛 UnsupportedEncodingException
Java 早期版本(Java 7 及以前)的 URLDecoder.decode(String, String) 要求显式传入字符集名,不传或传错会直接炸。很多人写成 URLDecoder.decode(s)(单参数),这方法在 Java 9+ 已被标记为 @Deprecated,且底层默认用 ISO-8859-1 —— 中文必然乱码。
正确做法始终用双参数重载,并固定为 UTF-8:
String decoded = URLDecoder.decode(encodedStr, "UTF-8");
- 别依赖系统默认编码,
UTF-8是 Web 事实标准 -
Java 8+虽允许单参数调用,但行为不可靠,一律规避 - 如果输入可能为空或 null,先判空,
URLDecoder不做空值防护
URLEncoder.encode() 编码后斜杠 / 和冒号 : 没变,导致 URL 路径断裂
URLEncoder.encode() 本意是编码“查询参数值”,不是整个 URL。它只对非字母数字及 - _ . ~ 进行百分号编码,而 /、:、? 等 URL 结构符原样保留 —— 所以若拿它去编码一个完整路径(如 /api/user/张三),结果会是 /api/user/%E5%BC%A0%E4%B8%89,其中 / 未被编码,服务器仍按路径分隔解析,导致路由匹配失败。
真正该做的,是只编码“值”部分,比如 name=张三 中的 张三:
立即学习“Java免费学习笔记(深入)”;
String url = "/api/user?name=" + URLEncoder.encode("张三", "UTF-8");- 永远只对 query parameter 的 value 单独编码,不要对 path segment 或整个 URL 调用
URLEncoder - path 中的中文应由上层框架(如 Spring MVC)自动处理,或手动用
java.net.URI构建(它会正确转义 path 部分) -
URLEncoder会把空格转成+,这是历史遗留;HTTP 规范中 query 里空格也接受+,但统一用%20更稳妥——可事后替换:str.replace("+", "%20")
Spring Boot 里 @RequestParam 接收中文参数仍然乱码
即使你前端用 encodeURIComponent() 编码、后端用 URLDecoder.decode(..., "UTF-8"),Spring 仍可能返回乱码。这不是 URLDecoder 的问题,而是 Spring 默认没设 query string 解码字符集。
需在配置中显式指定:
server.tomcat.uri-encoding=UTF-8
放在 application.properties 里。否则 Tomcat 用 ISO-8859-1 解 query,再交给 Spring,就晚了。
- 这个配置只影响 query string,不影响 POST body(body 编码由
Content-Type头和@RequestBody处理器决定) - Jetty 或 Undertow 用户需查对应容器的 URI 编码设置方式,不是所有容器都认这个 key
- 前端若用
fetch+URLSearchParams,它内部自动 UTF-8 编码,无需手动encodeURIComponent,但后端配置仍不可少
Java 11+ 有更安全的替代方案吗?
有。java.net.URLEncoder 和 URLDecoder 是老 API,线程安全但设计粗糙:不校验输入、不区分 context(query vs path)、异常信息模糊。Java 11 引入 java.net.URI 构造函数可自动处理 path 和 query 分别编码:
URI uri = new URI("https", "example.com", "/user/张三", "name=李四&city=北京", null);它内部对 path 使用 UTF-8 编码,query 部分也按规范处理,比手拼字符串+URLEncoder 更可靠。
-
URI构造器会抛URISyntaxException,比UnsupportedEncodingException更明确 - 不要用
URI.toString()直接发请求,它可能包含未编码的 Unicode 字符;要用uri.toASCIIString() - 复杂场景(如动态 query 构建)建议用
UriComponentsBuilder(Spring 提供),它封装了这些细节
实际用的时候,最常踩的坑不是不会写那两行 decode/encode,而是没想清楚“这段字符串到底属于 URL 的哪一部分”。path、query key、query value、fragment,每种上下文的编码规则和工具都不一样。一招鲜吃遍天,准乱码。










