如何在Java 8中规避JDK-8272702缺陷实现相对URI正确解析
解决Java 8中URI相对路径解析的JDK-8272702缺陷
Java 8的java.net.URI.resolve()方法存在JDK-8272702缺陷:当基础URI(base URI)没有末尾斜杠且路径为空时(如https://a.com),解析相对路径会错误拼接,例如将https://a.com和path拼成https://a.compath,而非预期的https://a.com/path。Java 21已修复该问题,以下是兼容Java 8的通用解决方案,支持所有URI协议。
实现思路
针对层次化URI(如HTTP/HTTPS/FTP等),如果基础URI的路径为空且无末尾斜杠,先为其添加单个斜杠,再调用原生resolve()方法;非层次化URI(如mailto)直接使用原生解析逻辑,无需调整。
代码实现
import java.net.URI; import java.net.URISyntaxException; public class UriResolver { public static URI resolveUri(URI baseUri, String relativePath) throws URISyntaxException { // 非绝对URI直接用原生解析 if (!baseUri.isAbsolute()) { return baseUri.resolve(relativePath); } // 非层次化URI(如mailto)无需调整,直接解析 if (baseUri.isOpaque()) { return baseUri.resolve(relativePath); } // 层次化URI:路径为空时,添加末尾斜杠 String basePath = baseUri.getPath(); URI adjustedBase = baseUri; if (basePath == null || basePath.isEmpty()) { adjustedBase = new URI( baseUri.getScheme(), baseUri.getUserInfo(), baseUri.getHost(), baseUri.getPort(), "/", baseUri.getQuery(), baseUri.getFragment() ); } return adjustedBase.resolve(relativePath); } // 测试示例 public static void main(String[] args) throws URISyntaxException { // HTTP基础URI无斜杠的情况 URI base = new URI("https://a.com"); System.out.println(resolveUri(base, "path")); // 输出: https://a.com/path // 带端口的HTTP URI base = new URI("http://localhost:8080"); System.out.println(resolveUri(base, "api/v1/users")); // 输出: http://localhost:8080/api/v1/users // 已有路径的基础URI base = new URI("https://a.com/foo"); System.out.println(resolveUri(base, "bar")); // 输出: https://a.com/bar // 非层次化mailto URI base = new URI("mailto:user@example.com"); System.out.println(resolveUri(base, "?subject=Greeting")); // 输出: mailto:user@example.com?subject=Greeting // FTP协议URI base = new URI("ftp://ftp.example.org"); System.out.println(resolveUri(base, "docs/readme.txt")); // 输出: ftp://ftp.example.org/docs/readme.txt } }
关键说明
- 协议兼容性:通过
isOpaque()区分层次化与非层次化URI,确保mailto、tel等特殊协议不受影响。 - 无侵入调整:仅在基础URI路径为空时添加斜杠,不改变已有路径的URI解析逻辑(如
https://a.com/foo解析bar仍得到https://a.com/bar)。 - 保留原属性:调整基础URI时,完整保留scheme、用户信息、主机、端口、查询参数、片段等所有原生属性。
- 异常兼容:抛出
URISyntaxException与原生URI方法一致,保持API行为一致性。
内容的提问来源于stack exchange,提问作者mkobit
相关产品推荐
相关产品推荐

