在Java开发中,从URL中提取服务器名称是常见需求,比如统计不同域名的访问量、做接口鉴权时校验请求来源等场景都会用到。服务器名称指的是URL中协议和路径之间的部分,包含主机名和端口(如果有端口的话)。

方法一:使用Java内置URL类实现
Java标准库的java.net.URL类已经封装了URL的解析逻辑,我们可以直接调用它的getHost()方法获取服务器名称,这种方式不需要自己处理复杂的URL格式,兼容性更好。
实现步骤
- 首先将字符串形式的URL转换为
URL对象 - 调用
URL对象的getHost()方法获取主机名 - 如果需要包含端口,再调用
getPort()方法,端口为-1表示使用默认端口,不需要拼接
完整代码示例
import java.net.URL;
public class UrlServerNameExtractor {
/**
* 使用URL类提取服务器名称,包含端口(如果有非默认端口)
* @param urlStr 完整的URL字符串
* @return 服务器名称,解析失败返回null
*/
public static String extractServerNameWithUrlClass(String urlStr) {
try {
URL url = new URL(urlStr);
String host = url.getHost();
int port = url.getPort();
// 端口为-1表示使用默认端口,不需要拼接
if (port != -1) {
return host + ":" + port;
}
return host;
} catch (Exception e) {
// 处理URL格式错误的情况
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
// 测试不同的URL场景
String[] testUrls = {
"https://www.ipipp.com/path/page.html",
"http://localhost:8080/api/user",
"ftp://192.168.0.1:21/files",
"https://www.ipipp.com:443/test"
};
for (String url : testUrls) {
String serverName = extractServerNameWithUrlClass(url);
System.out.println("URL: " + url);
System.out.println("服务器名称: " + serverName);
System.out.println("------");
}
}
}
方法二:使用字符串分割方式实现
如果不想依赖URL类,也可以通过字符串分割的方式手动提取服务器名称,这种方式更轻量,但需要自己处理各种边界情况。
实现逻辑
首先找到协议分隔符://的位置,然后截取后面的内容,再找到第一个/的位置,截取前面的部分就是服务器名称,同时需要处理没有路径的情况。
完整代码示例
public class UrlServerNameExtractorBySplit {
/**
* 使用字符串分割方式提取服务器名称
* @param urlStr 完整的URL字符串
* @return 服务器名称,解析失败返回null
*/
public static String extractServerNameBySplit(String urlStr) {
if (urlStr == null || urlStr.isEmpty()) {
return null;
}
// 查找协议分隔符的位置
int protocolIndex = urlStr.indexOf("://");
if (protocolIndex == -1) {
// 没有协议的情况,直接按路径分割
int pathIndex = urlStr.indexOf("/");
if (pathIndex == -1) {
return urlStr;
}
return urlStr.substring(0, pathIndex);
}
// 截取协议后面的内容
String afterProtocol = urlStr.substring(protocolIndex + 3);
// 查找第一个路径分隔符的位置
int pathIndex = afterProtocol.indexOf("/");
if (pathIndex == -1) {
// 没有路径的情况,整个afterProtocol就是服务器名称
return afterProtocol;
}
return afterProtocol.substring(0, pathIndex);
}
public static void main(String[] args) {
// 测试不同的URL场景
String[] testUrls = {
"https://www.ipipp.com/path/page.html",
"http://localhost:8080/api/user",
"ftp://192.168.0.1:21/files",
"https://www.ipipp.com:443/test",
"www.ipipp.com/test" // 无协议的情况
};
for (String url : testUrls) {
String serverName = extractServerNameBySplit(url);
System.out.println("URL: " + url);
System.out.println("服务器名称: " + serverName);
System.out.println("------");
}
}
}
两种方法的对比
我们可以通过下面的表格对比两种实现方式的优缺点,方便根据实际场景选择:
| 对比项 | URL类实现 | 字符串分割实现 |
|---|---|---|
| 实现复杂度 | 低,直接调用内置方法 | 高,需要手动处理边界逻辑 |
| 兼容性 | 好,支持各种标准URL格式 | 一般,特殊格式URL容易解析错误 |
| 性能 | 略低,需要创建URL对象,可能抛异常 | 略高,纯字符串操作 |
| 适用场景 | 处理标准URL,需要高兼容性 | 处理简单URL,追求轻量实现 |
注意事项
- 使用
URL类时,如果URL格式不合法会抛出MalformedURLException,需要做好异常处理 - 字符串分割方式无法处理包含特殊字符的非标准URL,比如URL中包含中文或者其他编码字符时容易出错
- 如果只需要主机名不需要端口,直接使用
getHost()方法即可,不需要额外拼接端口 - 测试时要覆盖带端口、不带端口、无路径、无协议等多种场景,避免遗漏边界情况
实际开发中建议优先使用URL类的实现方式,虽然性能略低,但兼容性和准确性更有保障,减少后续维护的成本。