You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中new URL()跨协议一致获取hostname与pathname的方法

如何忽略协议差异,统一获取URL的hostname和pathname?

在JavaScript中使用new URL()处理不同协议的URL时,会遇到标准协议(如http/https/ftp)和自定义协议(如atp)返回结果不一致的问题:

// 自定义协议atp的解析结果
const url1 = new URL("atp://abcd.com/person/items/1234");
console.log(url1);
// 输出:
// URL{
//     hash: ""
//     host: ""
//     hostname: ""
//     href: "atp://abcd.com/person/items/1234"
//     origin: "null"
//     password: ""
//     pathname: "//abcd.com/person/items/1234"
//     port: ""
//     protocol: "atp:"
//     search: ""
// }

// 标准协议http的解析结果
const url2 = new URL("http://abcd.com/person/items/1234");
console.log(url2);
// 输出:
// URL{
//     hash: ""
//     host: "abcd.com"
//     hostname: "abcd.com"
//     href: "http://abcd.com/person/items/1234"
//     origin: "http://abcd.com"
//     password: ""
//     pathname: "/person/items/1234"
//     port: ""
//     protocol: "http:"
//     search: ""
// }

可以看到,自定义协议的hostname为空,原本的域名被包含在pathname里,而标准协议能正确拆分域名和路径。

解决方案

可以通过两种方式实现统一解析:

方法1:手动修正自定义协议的解析结果

针对hostname为空且pathname以//开头的情况,手动拆分域名和路径:

function getStandardUrlParts(urlStr) {
  const url = new URL(urlStr);
  
  // 处理自定义协议的异常解析
  if (!url.hostname && url.pathname.startsWith('//')) {
    const [hostSegment, ...pathSegments] = url.pathname.slice(2).split('/');
    return {
      hostname: hostSegment,
      pathname: '/' + pathSegments.join('/'),
      protocol: url.protocol,
      fullUrl: url.href
    };
  }
  
  // 标准协议直接返回正常结果
  return {
    hostname: url.hostname,
    pathname: url.pathname,
    protocol: url.protocol,
    fullUrl: url.href
  };
}

// 测试用例
console.log(getStandardUrlParts("atp://abcd.com/person/items/1234"));
// { hostname: 'abcd.com', pathname: '/person/items/1234', protocol: 'atp:', fullUrl: 'atp://abcd.com/person/items/1234' }

console.log(getStandardUrlParts("http://abcd.com/person/items/1234"));
// { hostname: 'abcd.com', pathname: '/person/items/1234', protocol: 'http:', fullUrl: 'http://abcd.com/person/items/1234' }

方法2:临时替换协议为标准协议解析

把自定义协议临时替换成http,利用标准协议的解析逻辑获取正确的hostname和pathname,最后还原原协议:

function parseUrlUniformly(urlStr) {
  const protocolRegex = /^([a-z0-9-]+):\/\//i;
  const match = urlStr.match(protocolRegex);
  let tempUrl = urlStr;
  let originalProtocol = '';
  
  // 识别并替换自定义协议
  if (match) {
    originalProtocol = match[1] + ':';
    const standardProtocols = ['http:', 'https:', 'ftp:', 'ftps:'];
    if (!standardProtocols.includes(originalProtocol.toLowerCase())) {
      tempUrl = urlStr.replace(protocolRegex, 'http://');
    }
  }
  
  const url = new URL(tempUrl);
  return {
    hostname: url.hostname,
    pathname: url.pathname,
    protocol: originalProtocol || url.protocol,
    fullUrl: urlStr
  };
}

// 测试用例
console.log(parseUrlUniformly("atp://abcd.com/person/items/1234"));
// { hostname: 'abcd.com', pathname: '/person/items/1234', protocol: 'atp:', fullUrl: 'atp://abcd.com/person/items/1234' }

console.log(parseUrlUniformly("https://test.org/api/data"));
// { hostname: 'test.org', pathname: '/api/data', protocol: 'https:', fullUrl: 'https://test.org/api/data' }

原因说明

浏览器的URL对象仅对标准网络协议遵循URL分层结构解析,会自动拆分//后的内容为hostname和pathname;而自定义协议不在浏览器的标准协议列表中,URL对象会将//及后续内容全部当作pathname处理,导致hostname为空。

内容的提问来源于stack exchange,提问作者SThota

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 17:09:48