在Java开发中,获取域名是构建网络应用、处理请求转发以及生成动态链接的基础操作,核心上文归纳是:获取域名的方式取决于应用运行的环境,主要分为Web容器环境(如Spring Boot、Tomcat)和非Web环境,在Web环境中,应优先使用HttpServletRequest对象获取,并必须正确处理反向代理(如Nginx)传递的头部信息;在非Web环境中,则利用InetAddress类或URL解析类来实现。

基于Web容器环境的域名获取
在绝大多数Java Web应用中,获取当前请求的域名是最常见的需求,这通常通过处理HTTP请求对象来实现。
使用HttpServletRequest获取基础域名
最直接的方法是通过Servlet API提供的HttpServletRequest接口,该接口封装了客户端的所有请求信息。
核心方法是getServerName(),该方法返回请求头中的Host值,即浏览器请求的目标服务器名。
import javax.servlet.http.HttpServletRequest;
public String getDomainFromRequest(HttpServletRequest request) {
return request.getServerName();
}
仅仅使用getServerName()往往是不够的,在实际生产环境中,应用通常部署在负载均衡器或反向代理服务器(如Nginx、Apache)之后。request.getServerName()获取的可能是内部服务器的IP地址(如192.168.x.x)或者代理服务器的域名,而非用户在浏览器中输入的真实外部域名。
构建完整的访问URL(包含协议和端口)
为了获取完整的域名及上下文路径,通常需要将协议(http/https)、端口号以及上下文路径进行拼接。
关键点在于判断端口是否为默认端口:HTTP默认80端口,HTTPS默认443端口,如果是默认端口,在URL中应当省略端口号以保持美观。
public String getFullUrl(HttpServletRequest request) {
String scheme = request.getScheme(); // http 或 https
String serverName = request.getServerName(); // 域名
int serverPort = request.getServerPort(); // 端口
String contextPath = request.getContextPath(); // 应用上下文路径
StringBuilder url = new StringBuilder();
url.append(scheme).append("://").append(serverName);
// 只有非标准端口才拼接端口号
if ((scheme.equals("http") && serverPort != 80) ||
(scheme.equals("https") && serverPort != 443)) {
url.append(":").append(serverPort);
}
url.append(contextPath);
return url.toString();
}
处理反向代理与负载均衡场景
在现代微服务架构中,Java应用很少直接暴露在公网。专业级的域名获取方案必须能够识别反向代理传递的真实域名。
当请求经过Nginx等反向代理时,原始的Host信息可能会被覆盖,或者应用服务器接收到的Host是内网IP,为了解决这个问题,业界标准是检查特定的HTTP请求头。

识别X-Forwarded-Host头
X-Forwarded-Host是事实上的标准头部,用于记录原始请求的Host信息。X-Forwarded-Proto用于记录原始协议(http/https),X-Forwarded-Port用于记录原始端口。
最佳实践代码实现:
public String getRealDomain(HttpServletRequest request) {
// 1. 优先检查代理传递的域名
String domain = request.getHeader("X-Forwarded-Host");
// 2. 如果没有代理头,则使用默认的ServerName
if (domain == null || domain.isEmpty()) {
domain = request.getServerName();
}
return domain;
}
综合获取真实URL的完整方案
一个专业且健壮的工具类方法应当综合考虑所有因素:优先读取代理头,其次读取默认属性,并正确处理协议和端口。
public String getRealRequestURL(HttpServletRequest request) {
// 获取协议
String scheme = request.getHeader("X-Forwarded-Proto");
if (scheme == null || scheme.isEmpty()) {
scheme = request.getScheme();
}
// 获取域名
String serverName = request.getHeader("X-Forwarded-Host");
if (serverName == null || serverName.isEmpty()) {
serverName = request.getServerName();
}
// 获取端口
int serverPort = request.getServerPort();
String portHeader = request.getHeader("X-Forwarded-Port");
if (portHeader != null && !portHeader.isEmpty()) {
try {
serverPort = Integer.parseInt(portHeader);
} catch (NumberFormatException e) {
// 保持默认端口
}
}
// 拼接逻辑
StringBuilder url = new StringBuilder();
url.append(scheme).append("://").append(serverName);
if (("http".equalsIgnoreCase(scheme) && serverPort != 80) ||
("https".equalsIgnoreCase(scheme) && serverPort != 443)) {
url.append(":").append(serverPort);
}
return url.toString();
}
非Web环境下的域名获取
在某些后台任务、定时任务或非Web服务的Java应用中,不存在HttpServletRequest对象,此时需要依赖Java底层的网络API。
获取本机主机名
使用InetAddress.getLocalHost()可以获取本地主机的信息。
import java.net.InetAddress;
public String getLocalHostName() {
try {
return InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
return "Unknown";
}
}
注意: 此方法返回的是操作系统的主机名,不一定是对外暴露的域名,它依赖于/etc/hosts(Linux)或DNS解析,如果需要获取本机绑定的所有IP地址,可以使用InetAddress.getAllByName()。
解析字符串URL中的域名
如果手头有一个完整的URL字符串,需要从中提取出域名,可以使用java.net.URL类,这是最标准且不易出错的方式。
import java.net.URL;
public String extractDomainFromString(String urlString) {
try {
URL url = new URL(urlString);
return url.getHost(); // 仅返回域名,不包含协议和端口
} catch (Exception e) {
return null;
}
}
安全性与E-E-A-T原则下的注意事项
在处理域名获取时,安全性是不可忽视的一环。

-
防止Host Header注入攻击:
由于getServerName()和getHeader("Host")的数据完全来源于用户提供的HTTP请求头,恶意用户可以伪造Host头,将Host设置为evil.com,如果你的应用直接使用这个域名生成密码重置链接,或者将其包含在敏感的页面跳转中,可能会导致安全漏洞。解决方案:对于关键业务,不要直接信任请求中的Host值,应当配置一个允许的域名白名单,或者从配置文件中读取基准域名,仅在多租户等特定场景下才解析请求头。
-
空值与异常处理:
在网络编程中,任何IO操作都可能失败,无论是InetAddress的操作还是URL的解析,都必须进行try-catch包裹,并提供合理的降级方案,避免因域名获取失败导致整个应用崩溃。
相关问答
Q1:在Spring Boot中,有没有更简单的方式获取当前服务器的域名?
A: Spring Boot提供了HttpServletRequest自动注入,你可以直接在Controller中使用上述方法,如果你需要获取服务器自身的配置信息(而非请求中的域名),可以使用ServerProperties类或通过Environment对象读取server.address配置,但请记住,配置文件中的地址通常是静态的,无法反映经过反向代理后的真实动态域名。
Q2:为什么我的Java程序获取到的域名是127.0.0.1而不是公网IP?
A: 这种情况通常发生在反向代理配置不正确,或者程序直接监听本地回环地址时,首先检查Nginx等代理配置是否正确转发了Host和X-Forwarded-For头,检查/etc/hosts文件是否将本机主机名解析到了127.0.0.1,在非Web环境下,InetAddress.getLocalHost()的行为严格遵循操作系统的网络配置。
能帮助你全面掌握Java中获取域名的各种技巧,如果你在实际项目中遇到了特殊的网络架构(如多层代理或云原生Service Mesh环境),欢迎在评论区分享你的配置方案,我们可以共同探讨更优的解决思路。

















