紀錄工作經驗、相關知識,解決技術相關問題。

Javascript

[JS] JavaScript 取得網址目前的網域名稱:location.hostname 用法、環境判斷與子網域拆解

[JS] JavaScript 取得網址目前的網域名稱:location.hostname 用法、環境判斷與子網域拆解 特色圖片

在前端開發中,當我們需要用 JavaScript 取得當前網址(URL)的純網域名稱(Domain Name)時,最標準且安全的屬性是 window.location.hostname。與會連帶回傳連接埠號的 location.host 不同,location.hostname 永遠只回傳純淨的網域字串(不含 :8080 或 :3000),非常適合用於環境判斷、Cookie 網域設定與子網域解析。

⚡ 快速跳轉(依實務情境選擇):

基本語法:取得純網域名稱(自動忽略連接埠)

假設當前網址為:

https://www.seanacnet.com:8080/js/location-hostname.html?id=111&t=9#template

使用範例:

// 取得純網域名稱(自動忽略 :8080 連接埠號)
const domain = window.location.hostname;

console.log(domain);
// 輸出: "www.seanacnet.com"

即使當前網址帶有非預設連接埠(如本地開發常見的 http://localhost:3000 或測試機 https://staging.seanacnet.com:8080),location.hostname 依然只會回傳 "localhost" 與 "staging.seanacnet.com",不會混入冒號與連接埠號。

實務場景一:為什麼判斷 localhost 與正式機環境必用 hostname?

在專案開發中,工程師常需要根據當前網址判斷目前處於「本地開發環境(Local)」、「測試環境(Staging)」還是「正式環境(Production)」,藉此切換除錯日誌或第三方追蹤碼。

❌ 常見踩坑寫法:誤用 location.host 導致本地開發判斷失效

若在本地啟動 Vite(:5173)或 Next.js / React(:3000)開發伺服器,網址為 http://localhost:3000/dashboard:

// ❌ 錯誤示範:location.host 會包含 ":3000",導致嚴格相等比對回傳 false
if (window.location.host === 'localhost') {
  console.log('目前為本地開發環境'); // 永遠不會執行!因為 location.host 是 "localhost:3000"
}

✅ 標準防呆寫法:使用 location.hostname 進行環境判定

改用 location.hostname 後,無論本地開發伺服器掛在哪一個連接埠號,都能精準匹配網域:

function getRuntimeEnvironment() {
  const hostname = window.location.hostname;

  // 涵蓋 localhost、IPv4 迴路位址與 IPv6 迴路位址
  if (
    hostname === 'localhost' ||
    hostname === '127.0.0.1' ||
    hostname === '[::1]'
  ) {
    return 'local';
  }

  // 判斷測試機子網域(例如 staging.example.com 或 dev.example.com)
  if (hostname.startsWith('staging.') || hostname.startsWith('dev.')) {
    return 'staging';
  }

  return 'production';
}

console.log(getRuntimeEnvironment());
// 於 http://localhost:3000 執行輸出: "local"

實務場景二:拆解子網域(Subdomain)與主網域實作範本

在多租戶(Multi-tenant)SaaS 系統或跨子網域共用 Cookie 的架構中,常需要從 location.hostname 提取出「租戶子網域(例如 shop-a.seanacnet.com 中的 shop-a)」或「根網域(Root Domain)」。

以下工具函式同時處理了台灣常見的雙層國碼頂級網域(如 .com.tw、.org.tw)以及 localhost / IP 位址邊界情況:

function parseDomainParts(hostname = window.location.hostname) {
  // 排除 localhost 與純 IPv4 / IPv6 位址
  const isIpOrLocal =
    hostname === 'localhost' ||
    /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) ||
    hostname.startsWith('[');

  if (isIpOrLocal) {
    return { hostname, rootDomain: hostname, subdomain: '' };
  }

  const parts = hostname.split('.');
  // 判斷是否為台灣常見的雙層頂級網域(如 .com.tw, .org.tw, .edu.tw, .gov.tw)
  const isTwoLevelTld =
    parts.length >= 3 &&
    parts[parts.length - 1] === 'tw' &&
    ['com', 'org', 'edu', 'gov', 'net', 'idv'].includes(parts[parts.length - 2]);

  const rootSegmentsCount = isTwoLevelTld ? 3 : 2;

  if (parts.length <= rootSegmentsCount) {
    return { hostname, rootDomain: hostname, subdomain: '' };
  }

  const rootDomain = parts.slice(-rootSegmentsCount).join('.');
  const subdomain = parts.slice(0, -rootSegmentsCount).join('.');

  return { hostname, rootDomain, subdomain };
}

// 範例 1:一般子網域
console.log(parseDomainParts('blog.seanacnet.com'));
// 輸出: { hostname: "blog.seanacnet.com", rootDomain: "seanacnet.com", subdomain: "blog" }

// 範例 2:台灣雙層國碼網域
console.log(parseDomainParts('member.shop.example.com.tw'));
// 輸出: { hostname: "member.shop.example.com.tw", rootDomain: "example.com.tw", subdomain: "member.shop" }

location.hostname、host 與 origin 差異對照表

假設當前頁面網址為 https://www.seanacnet.com:8080/products/item?id=10,以下為相關網域屬性的回傳值與選用時機比較:

屬性名稱回傳結果範例是否含連接埠 (Port)典型工程適用場景
location.hostname"www.seanacnet.com"❌ 不包含判斷 localhost 環境、拆解子網域、設定 Cookie domain
location.host"www.seanacnet.com:8080"✅ 包含(非預設埠)動態組裝 WebSocket(ws://${location.host})或同主機連線
location.origin"https://www.seanacnet.com:8080"✅ 包含協定+網域+埠組合 API Base URL、postMessage 跨視窗來源安全驗證
location.port"8080"僅連接埠字串單獨檢查當前伺服器是否運行於特定開發連接埠

常見問題與瀏覽器相容性排查

Q1:直接賦值修改 location.hostname 會發生什麼事?

  • 行為說明:location.hostname 並非唯讀屬性。當你執行 window.location.hostname = 'm.seanacnet.com' 時,瀏覽器會立即觸發頁面跳轉,並保留原本的路徑(pathname)、查詢參數(search)與錨點(hash)。
  • 注意事項:若原網址帶有非預設連接埠(例如 http://dev.seanacnet.com:8080/login),單獨修改 location.hostname 不會清除原本的 :8080。若目標網域並未開放 8080 連接埠,應改用 location.host 或 location.href 進行完整跳轉。

Q2:瀏覽器相容性如何?

location.hostname 屬於 Web API 標準核心屬性,支援所有現代桌面與行動端瀏覽器(Chrome、Edge、Firefox、Safari、Opera)。詳細規格可參考 MDN Web Docs: Location.hostname。

如果你還想進一步了解 JavaScript 取得 URL 的其他參數,可前往以下總整理與專篇查詢:

發表迴響