准确获取当前域名和子域名的核心方法,就是用好window.location对象里的hostname、host和origin三个属性,再配合URL构造函数或字符串拆分,就能分清纯域名、带端口域名和完整域名部分。
js获取当前域名的方法:hostname与host的取舍
要想准确获取当前域名,必须先搞清楚window.location对象到底提供了什么,它就像页面地址的解剖师,把一串完整URL拆成协议、域名、端口、路径、参数和哈希,其中和域名直接相关的属性有三个:hostname、host、origin。
先看一个具体场景,假设当前页面地址是:
https://blog.example.com:8443/search?q=js#top
window.location各属性的返回值如下:
| 属性 | 返回值 | 说明 |
|---|---|---|
| href | https://blog.example.com:8443/search?q=js#top | 完整地址 |
| protocol | https: | 协议,含冒号 |
| host | blog.example.com:8443 | 域名+端口 |
| hostname | blog.example.com | 纯域名,不含端口 |
| port | 8443 | 端口号 |
| origin | https://blog.example.com:8443 | 协议+域名+端口 |
| pathname | /search | 路径 |
| search | ?q=js | 查询参数 |
| hash | #top | 哈希片段 |
从这张表能看出,js获取当前域名的方法里,hostname最符合直觉,它直接返回不含协议、不含端口、不含路径的纯域名。
const domain = window.location.hostname; console.log(domain); // "blog.example.com"
如果需要带端口的域名,才改用host,例如本地调试时地址为http://127.0.0.1:3000,此时hostname是0.0.1,host是0.0.1:3000,用错属性会丢掉端口信息,导致接口拼接错误。
据MDN Web Docs说明,location.hostname是只读字符串,返回URL中的域名部分,这个值不包含端口号,也不包含协议头,日常开发里,统计上报、埋点字段、后端域名白名单、环境判断,优先使用hostname。
业内专家指出,前端在做域名判断时最容易踩的坑,就是把host当hostname用,结果在非默认端口场景下拿到意外值,只要记住:hostname纯域名,host域名加端口,基本不会错。
js获取完整url的域名部分与子域名列表
仅仅获取hostname还不够,很多业务需要从任意一段URL字符串中提取域名,而不是只针对当前页面,这时候就要用URL构造函数。
js获取完整url的域名部分
假设你拿到的是一个接口返回的跳转地址、用户输入的链接,或者拼接后的完整URL字符串,不能直接访问window.location,因为location只描述当前页面,正确做法是用URL对象解析。
const targetUrl = 'https://a.b.example.com/path?from=home'; const url = new URL(targetUrl); const domainPart = url.hostname; console.log(domainPart); // "a.b.example.com"
URL构造函数会把协议、域名、端口、路径、参数全部分离,取hostname就得到完整url的域名部分,不会把路径或参数混进去,这个做法同样适用于当前页面:
const currentDomain = new URL(window.location.href).hostname;
两种方式结果一致,但URL对象能处理任意字符串,更适合封装成工具函数。
js获取子域名列表
浏览器没有提供直接返回子域名数组的API,需要自己从hostname拆分,拆分逻辑不复杂:
const hostname = 'a.b.example.com';
const parts = hostname.split('.');
console.log(parts); // ["a", "b", "example", "com"]
从数组里去掉最后两段主域名,剩下的就是子域名片段:
function getSubdomainParts(hostname) {
const parts = hostname.split('.');
return parts.length > 2 ? parts.slice(0, -2) : [];
}
console.log(getSubdomainParts('a.b.example.com')); // ["a", "b"]
console.log(getSubdomainParts('example.com')); // []
但这里有个隐藏问题:不是所有域名都恰好由“主域名+两段后缀”组成,国内不少站点使用com.cn、net.cn、org.cn等双后缀,例如www.example.com.cn,按“去掉最后两段”会错误地把example当成子域名,实际上主域名是example.com.cn,真正的子域名只有www。
行业共识认为,前端无法仅靠原生API精确识别所有公共后缀,涉及com.cn、co.uk这类双后缀时,必须维护公共后缀列表,或者使用专门处理域名边界的第三方库,如果业务只处理自己公司固定的域名,可以在代码里硬编码主域名根,用字符串替换:
const mainDomain = 'example.com';
const hostname = 'a.b.example.com';
const subdomainPart = hostname.replace('.' + mainDomain, '');
console.log(subdomainPart); // "a.b"
这种方式简单可控,适合内部系统,对开放平台或者不确定域名后缀的场景,则需要公共后缀数据兜底。
前端怎么获取当前域名和端口?场景化拆解
这个需求通常出现在环境判断、接口根地址拼接、登录回调地址生成等场景,不同场景对“域名和端口”的要求不一样,要分清楚。
前端怎么获取当前域名和端口?一行代码拆解
最直接的方式就是读取location.host。
const domainWithPort = window.location.host; console.log(domainWithPort); // "blog.example.com:8443"
host已经包含端口号,如果当前页面是默认端口,比如https的443或http的80,host会自动省略端口,只返回纯域名。
// 页面地址为 https://example.com/search console.log(window.location.host); // "example.com" console.log(window.location.hostname); // "example.com" console.log(window.location.port); // ""
可以看到,默认端口下port是空字符串,host和hostname完全相同,这个特性在很多代码里被直接利用,用来拼接接口地址。
const apiBase = window.location.protocol + '//' + window.location.host + '/api';
这样写出来的apiBase会自动适应当前协议和端口,不会在https页面请求http接口,也不会丢掉本地调试端口。
js获取当前域名不包括端口的两种写法
如果只想要纯域名,不要端口,有两种常用写法。
写法一,直接读取hostname:
const noPort1 = window.location.hostname;
写法二,通过URL对象再取hostname:
const noPort2 = new URL(window.location.href).hostname;
两种方法结果一样,区别在于,第一种只能用于当前页面,第二种可以处理任意URL字符串,写公共工具函数时,用第二种更灵活:
function getDomainWithoutPort(urlStr) {
return new URL(urlStr).hostname;
}
对于IP地址形式的域名,hostname同样有效,例如http://192.168.1.10:8080,hostname返回168.1.10,不会带端口,IPv6地址会被URL对象处理成不带方括号的形式,但location.hostname在部分旧浏览器中可能保留方括号,需要做兼容处理。
多级子域名判断:从正则到URL API
很多场景不只是提取域名,还要判断当前处于几级子域名,例如不同租户使用不同子域名,前端要根据子域名加载不同主题或数据。
判断子域名层级,本质是计算hostname里点的数量,一个最简版本:
function getSubdomainDepth(hostname) {
const parts = hostname.split('.');
// 默认最后两段为主域名,如 example.com
return parts.length > 2 ? parts.length - 2 : 0;
}
console.log(getSubdomainDepth('www.example.com')); // 1
console.log(getSubdomainDepth('a.b.example.com')); // 2
console.log(getSubdomainDepth('example.com')); // 0
这个函数在后缀为单段的场景下够用,但如果碰到www.example.com.cn,它会返回2,实际上子域名层级是1,据统计,国内部分企业站点使用双后缀域名,这类错误在跨租户系统中并不少见。
一个更稳妥的思路是:先确定主域名根,再从完整域名中去掉主域名,再切分剩余部分。
function splitSubdomains(hostname, mainDomain) {
const suffix = '.' + mainDomain;
if (!hostname.endsWith(suffix)) return [];
const sub = hostname.slice(0, -suffix.length);
return sub ? sub.split('.') : [];
}
console.log(splitSubdomains('a.b.example.com.cn', 'example.com.cn'));
// ["a", "b"]
这个方法把主域名当作配置项传入,不受后缀长度影响,准确性更高,最适合业务域名固定的项目。
如果想彻底摆脱主域名配置,可以结合浏览器的URL API解析,再使用公共后缀列表过滤,公共后缀列表记录了全球所有顶级域和常见双后缀,但这已经超出原生JS能力范围,需要引入数据文件或第三方包。
常见坑与兼容性处理
坑一:字符串截取域名
不要用indexOf或者正则从location.href里截域名,URL一旦出现端口、参数、特殊字符,字符串截取就很容易出错。
// 错误示范
const wrongDomain = location.href.split('/')[2];
这行代码在https://example.com/path下能拿到example.com,但在https://example.com:8080/path下拿到的是example.com:8080,不要用它来处理域名提取。
坑二:URL构造函数的兼容性
现代浏览器都支持URL构造函数,但部分旧版IE不支持,需要兼容旧浏览器时,可以用document.createElement(‘a’)节点来解析。
function parseHostname(urlStr) {
const a = document.createElement('a');
a.href = urlStr;
return a.hostname;
}
这个方案在绝大多数浏览器中都有效,包括一些不支持URL构造器的旧环境,不过使用createElement(‘a’)解析相对路径时,会基于当前页面地址生成完整域名,需要先确认传入的是完整URL。
坑三:origin与hostname的边界
origin返回协议+域名+端口,但不含路径,它和host、hostname的差异在跨域判断、postMessage通信中很关键。
const origin = window.location.origin; const host = window.location.host; const hostname = window.location.hostname;
如果当前地址是https://example.com:8443,origin是https://example.com:8443,host是example.com:8443,hostname是example.com,跨域比较时要用origin,域名判断时用hostname,拼接接口根地址时用host。
坑四:localhost与127.0.0.1
本地开发时,location.hostname返回localhost或0.0.1,host为空时返回相同值,但两者在浏览器安全策略上不是完全等同,涉及cookie、跨域、CORS配置时,不要把localhost和0.0.1当成同一个域名处理,前端获取当前域名信息时,应该原样保留这两个值,不要做额外转换。
掌握location对象和URL解析的边界,就能在前端准确获取当前域名、端口和子域名层级,避免字符串硬切带来的隐藏Bug。
关于js获取当前域名信息的常见问题
js获取当前域名的方法中host和hostname有什么区别?
host返回域名加端口号,hostname只返回域名,比如访问https://a.example.com:8080/x,location.host是a.example.com:8080,location.hostname是a.example.com,默认端口下,host会省略端口,此时两者返回值相同。
js获取完整url的域名部分会不会包含路径和参数?
不会,如果直接读取window.location.href,会得到包含路径、参数和哈希的完整字符串,必须使用URL构造函数或document.createElement(‘a’)解析后取hostname属性,才能拿到不带路径和参数的纯域名部分。
前端怎么获取当前域名和端口,同时排除默认端口?
先读取location.host,再判断location.port是否为空,若port为空,说明当前协议使用默认端口,host本身就不含端口;若port有值,则host为“域名:端口”,这个判断逻辑在http默认80、https默认443的场景下都成立。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/646554.html





