JS动态获取域名并不复杂,最标准的方法是使用window.location对象,但在本地调试、跨域请求和端口处理上,很多开发者会踩坑。下面我将从最常用的属性组合讲起,逐步拆解不同场景下的取值差异,帮助你一次性把域名获取这件事彻底搞明白。
window.location实战:JS获取当前页面域名的5种写法
在浏览器环境中,window.location 对象身上几乎保存了当前URL的所有秘密,处理“JS如何获取域名”问题,本质就是搞懂这个家族里几个属性的分工。
window.location.href:返回完整URL,https://www.example.com:8080/path/page.html?id=1。window.location.hostname:只返回主机名,不带协议、端口和路径,结果是www.example.com。window.location.host:返回主机名加端口(如果端口是默认的80或443,通常会被省略),www.example.com:8080。window.location.protocol:返回协议部分,结果是https:(注意冒号)。window.location.origin:返回协议加主机加端口,较新的浏览器都支持,结果是https://www.example.com:8080。
从完整URL字符串中解析域名
如果你手里只有一个完整的URL字符串,而不是当前页面的地址,那就没法直接用 location 对象,这时候模拟浏览器解析行为有三种常见路子。
- 创建一个
<a>标签并赋值,利用浏览器的原生解析能力:
function getDomainFromUrl(url) {
var a = document.createElement('a');
a.href = url;
return a.hostname;
}
这是业内普遍认可的一种轻量方案,因为不需要引入正则库,处理各种畸形URL时浏览器会替你做容错,比手写正则靠谱得多。
- 使用
new URL()构造函数,这是现代浏览器和Node.js都能跑的方案:
var urlObj = new URL('https://blog.example.com/post/101');
console.log(urlObj.hostname); // 输出 blog.example.com
- 手写正则做切割,这种方式容易在处理带端口或带认证信息的URL时出错,除非在做非常复古的字符串解析,否则不推荐作为首选。
直接读hostname属性:最纯粹的取域名方式
在多数不涉及端口的场景下,window.location.hostname 是性价比最高的选择,它天然剥掉了协议头、端口号、查询参数和Hash,得到的就是干净的带子域名的完整主机名。
var currentDomain = window.location.hostname; // 如果当前地址是 https://aaa.bbb.com:8080/x,结果就是 aaa.bbb.com
如果你需要把域名中的 www 前缀去掉,可以配合 replace 方法处理:
var noWWW = window.location.hostname.replace(/^www./, '');
location对象其他属性的边界提醒
location.port 返回端口字符串,如果URL没有显式端口,BOM规范要求返回空字符串 ,正因为这个特性,直接拼接 “域名:端口” 时,必须判断一下端口是否为空,否则会出现 example.com: 这种半吊子字符串,获取动态端口推荐使用 location.port || (location.protocol === 'https:' ? '443' : '80') 这种保守写法。
JS获取域名带端口还是去掉端口?两种常见场景对比
很多新手分不清 host 和 hostname,搞混的直接后果就是接口请求签名校验失败,或者cookie作用域写错,说白了,带端口用 location.host,只要域名用 location.hostname,具体怎么选,取决于下游接受什么格式。
场景里比较典型的是后端联调,后端接口校验来源域名时,如果用 location.host,本地开发环境返回 localhost:5173,而后端白名单里只写了 localhost,校验立刻挂掉,这时候需要的是 hostname。
| 使用场景 | 推荐属性 | 举例结果 |
|---|---|---|
| 拼接WebSocket或API完整地址 | location.host |
api.example.com:8443 |
| 写入cookie的domain字段 | location.hostname |
example.com |
| 判断是否处于生产环境 | location.hostname |
app.example.com |
| 整站跨域白名单比对 | location.host |
app.example.com:3000 |
| 动态设置静态资源CDN前缀 | location.protocol + '//' + location.host |
https://app.example.com:3000 |
表单提交与接口跨域场景下的域名策略
在登录态验证和接口鉴权这类场景中,前后端常就因为多带了个端口闹出401,技术上,客户端拿到的 Origin 头里包含了完整的协议、域名和端口,服务端做 Access-Control-Allow-Origin 回显时也会把端口带回来,如果前端只传 hostname,而实际请求是从带端口的开发服务器发出的,跨域预检就会因为源不匹配被拦下,行业共识认为,凡是设计到跨域资源共享的服务端配置,前端都应该传完整的
origin 或 host,而不是只丢一个主域名过去。
本地调试与线上部署的环境差异
本地 localhost:8080 和线上 www.example.com 获取到的域名长度和层级完全不同,本地开发时,用 host 去区分不同端口起的多个本地服务(比如前端页面在3000端口,Mock接口在3001端口),这招很有效,能避免把Mock环境误请求到线上,但上线后,nginx做了反向代理,把请求分发到不同内部服务时,location.host 拿到的还是用户浏览器地址栏里那个域名,不受代理影响,这点需要心里有数。
开发场景落地:JS如何动态获取域名并拼接接口地址
搞清楚原理还远远不够,大多数业务场景里,拿到域名只是第一步,后面还得带着域名去做各种拼接,这里列举几个真实能上手的操作路径。
场景A:按运行环境切换API请求地址
这是中后台项目最日常的需求,本地连测试环境,测试环境连预发,预发连生产,最土的办法是写死配置文件,但每次打包都要改代码,动态获取域名可以这样设计规则:约定所有环境都用同一个域名前缀来区分。
var hostname = window.location.hostname;
// 假设测试环境域名是 test-api.example.com,生产是 api.example.com
var apiRoot = '/api/v1';
if (hostname.indexOf('localhost') > -1) {
apiRoot = 'http://test-api.example.com/api/v1';
} else {
apiRoot = window.location.protocol + '//' + hostname.replace(/^www./, 'api.') + '/api/v1';
}
这个写法虽然朴素,但胜在逻辑透明,不少老项目都在用类似模式,后来才逐步迁移到 VITE_APP_API 这类构建期环境变量,对原生HTML项目或者轻量模板引擎项目来说,动态获取域名更加省事。
场景B:SPA前端路由的base路径拼装
Vue Router 或 React Router 通常用 base 参数指定路由根路径,如果项目部署在二级目录,https://example.com/static/admin/,硬编码base路径换个环境就崩,借助 location.pathname 配合域名获取可以直接推导出所属目录。
var currentPath = window.location.pathname; // /static/admin/index.html
var basePath = currentPath.substring(0, currentPath.lastIndexOf('/') + 1); // /static/admin/
这样动态取出来的base值,无论部署到哪个目录,前端路由都能自适应,不需要重新构建发布。
场景C:分享链接和二维码的完整地址组装
在H5页面分享海报往往是开门见山给一个短链接,这个短链接需要和 origin 拼接,直接用 location.href.split('#')[0] 会把当前页面的各种参数都带上,不够干净,规范做法是取 location.origin + location.pathname 作为分享基址,再接上自己定义的渠道参数。
var shareBase = window.location.origin + window.location.pathname; var shareUrl = shareBase + '?inviter=9527&channel=wechat';
这样分享出去的链接不仅行为可控,还能避开原页面URL里残留的推广参数。
常见错误与兜底方案:为什么取域名会莫名失败
有些开发者会遇到 “JS获取不到域名” 或 “获取的是undefined” 的诡异问题,这和 window.location 本身关系不大,多半是执行上下文搞错了。
在 Web Worker 中无法访问 window
Web Worker 是独立的线程环境,里面没有 window 对象,自然也没有 window.location,标准做法是使用 self.location,然后在 Worker 内部重新解析,还有一种绕路方案,是主线程先把 location.hostname 通过 postMessage() 传给 Worker。
非浏览器环境运行
Node.js 环境里既没有 window 也没有 location,获取域名必须靠 os.hostname() 拿操作系统的主机名,或者解析请求头里的 Host 字段以获取HTTP服务的对外域名,这和前端完全是两套逻辑,不能用浏览器那套代码硬套。
脚本放在iframe中嵌套时的域名跳变
如果当前页面是iframe嵌套的,window.location 指向iframe内层文档地址,而不是外层浏览器的地址栏,这就是经典的三层域名访问难题,跨域iframe之间要通过 document.referrer 或者postMessage通信来拿到外层域名,如果是同域iframe,可以直接用 window.parent.location.hostname。
Q&A:JS动态获取域名的常见疑惑
JS如何同时获取域名和端口号?
如果需要同时拿到域名和端口号,window.location.host 一步到位,它天然是 “域名:端口” 的格式,不用自己拼接,如果不需要端口,就用 window.location.hostname,判断环境中是否有端口,可以看 window.location.port 是否为空字符串。
在浏览器控制台里如何快速测试获取域名?
在开发者工具的Console面板直接输入 location.hostname 回车,会立刻返回当前页面的域名,输入 location.origin 会返回协议加域名加端口,这个技巧在爬虫调试和接口联调时非常方便,不用写一整行代码就能确认页面当前所在环境。
动态获取的域名和手动输入为什么不一样?
如果域名解析采用了CDN加速或智能DNS调度,浏览器地址栏里看到的主机和后端实际收到请求的Host可能不完全一致,前端JS读取 location.host 永远反映浏览器的可视地址,而不是CDN内部节点域名,另一个高发原因是页面被HTTPS升级,location.protocol 会变成 https: 而手动配置里还是旧链接,端口也可能从80跳成443,这种情况下,不推荐在代码里硬编码协议,直接取 location.protocol 最稳妥。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/625847.html





