malformedurlexception 是检查型异常,当 java.net.url 构造器解析字符串时发现协议缺失、冒号错位、主机名不合法等 rfc 2396 语法错误时抛出,仅校验格式,不验证域名真实性或端口可达性。

MalformedURLException 是什么异常,什么时候抛出
它不是运行时随便报的错,而是 java.net.URL 构造器在解析字符串时,发现协议名缺失、冒号位置错、主机名不合法等硬性语法问题,直接拒绝构造对象时抛出的检查型异常。比如传入 "http//example.com"(少了个冒号)或 "ftp://"(没主机),new URL(...) 就会炸。
注意:它不校验域名是否真实存在、端口是否开放、路径是否存在——只管字符串格式合不合 RFC 2396 的基本规则。
别用 try-catch 包裹 new URL() 做“校验”,改用 URI + isAbsolute()
很多人写校验逻辑是这样:
try {
new URL(input);
return true;
} catch (MalformedURLException e) {
return false;
}
这看似可行,但有三个实际问题:
立即学习“Java免费学习笔记(深入)”;
-
URL构造器会尝试解析并规范化输入(比如把http://EXAMPLE.COM转成小写),还可能触发 DNS 查询(某些 JDK 版本对主机名做隐式解析),性能不可控 - 它对相对 URL(如
"./api/user")直接报错,但你可能想接受相对路径 - 部分合法 URI(如含空格未编码的
"https://site.com/hello world")会被URL拒绝,但其实URI能处理得更宽松
更稳的做法是用 java.net.URI:
try {
URI uri = new URI(input);
return uri.isAbsolute(); // 或根据需要放宽为 !uri.isOpaque()
} catch (URISyntaxException e) {
return false;
}
真正要校验“可用 URL”,得拆开看协议、主机、端口
光过得了 URI 构造还不等于能发 HTTP 请求。比如 "file:///etc/passwd" 是合法 URI,但你显然不想让它进网络请求逻辑;"http://127.0.0.1:65536" 协议和主机没问题,但端口超出范围(0–65535),后续连接必失败。
建议分层校验:
- 先用
new URI(input)确保基础语法正确 - 再检查
uri.getScheme()是否在白名单里(如"http"、"https",排除"file"、"jar") - 用
uri.getHost()非空且不为"localhost"或私有网段(如"10.0.0.1")——如果业务不允许内网调用 - 若需端口,检查
uri.getPort()是否在有效范围内,或默认值是否合理(-1表示用协议默认端口)
Spring 或 OkHttp 场景下,MalformedURLException 可能被底层吞掉
比如用 RestTemplate 发请求,传入非法 URL 字符串,它内部会调 new URL(),但错误可能被包装成 ResourceAccessException 或 IllegalArgumentException 向上抛,原始 MalformedURLException 被吃掉了,日志里看不到关键线索。
排查时别只盯着最终异常类型,要在调用链里加断点,或提前用 URI 校验输入——尤其当你的 URL 是拼接出来的(如 baseUrl + "/user/" + id),id 里混入了特殊字符又没编码,就很容易在这里翻车。
最常被忽略的一点:URL 字符串里的中文、空格、#、? 等必须先用 URLEncoder.encode(..., "UTF-8") 编码路径段,而不是整个 URL 丢进去——否则 URI 构造也可能失败,而且错误提示极不直观。










