WebGL Tutorial
and more

URL

撰写时间:2024-12-26

修订时间:2025-03-26

URL的构成

URL,全称为Uniform Resource Locator,即标准资源定位器,是通过互联网上唯一的地址来定位各种网络资源的机制。在JavaScript对应的类为URL。下面是创建指向当前页面的URL的一个实例的例子:

let url = new URL('docs/javascript/url/index.php', 'https://www.sarkuya.com'); pc.log(url);

在其构造器中,第一个参数为以相对路径的方式来指定,第二个参数是基本路径 (base url)。在所创建的url中,这两部分将自动组合为一个完整的路径。

URL有众多与网络地址相关的属性。下面列出了一些经常出现的属性:

let url = new URL('docs/javascript/url/index.php?username=Mike#sect-1', 'https://www.sarkuya.com:80'); function display(propName) { pc.log(`${propName}: ${url[propName]}`); } let propNames = [ 'href', 'pathname', 'protocol', 'hostname', 'port', 'host', 'origin', 'searchParams', 'hash' ]; propNames.forEach(display);

其中,href是最全的地址。pathname是剥离了其他辅助元素之后、比较干净的的当前网页地址的相对路径,根据此特点,我们经常使用该属性来动态地构建不同的URL

protocol是网络协议,hostname是网站名称,port的端口号,默认为80(另一个也较常见的端口号为8080)。

host = hostname + port

origin = protocol + host

因此,origin是成分较为齐备的网站名称。

searchParams是请求参数。hash指向当前网页中的特定锚点(anchor)。

URL构造器的参数中,hash应是放在最后的一个属性,须排在searchParams属性之后。如果hash排在searchParams之前,则searchParams的值将为空字符串,而hash的值将为#sect-1?username=Mike,从而导致出现一个不易觉察的错误。

window.location

构建URL

可通过location对象,根据当前请求页面地址,来快捷地构建一个URL

let location = window.location; pc.log(location); pc.log(location.href === document.baseURI); let url = new URL('./test.html', location); pc.log(url);

尽管documentbaseURI属性值与locationhref属性值一样,但前者是一个字符串,无法解析出第一节所示的各个成分,因此前者缺乏一定的灵活性。

注意到locationurl这两个变量分别属于LocationURL不同的类型。这两种类型有较多相同的属性名称,但各自都有自己独有的属性名称(确切来说,Location的属性都是自身属性,而URL的属性都是prototype属性)。下面是它们的属性名称两相比较的结果。

const {PrototypeUtils} = await import('/js/esm/PrototypeUtils.js'); let location = window.location; let url = new URL('./test.html', location); let locationPropNames = PrototypeUtils.GetPropNamesInPrototypeChain(location); let urlPropNames = PrototypeUtils.GetPropNamesInPrototypeChain(url); let comparedObj = PrototypeUtils.GetComparedArrays(locationPropNames, urlPropNames); pc.log('Properties that exists in both:'); pc.log(comparedObj.both); pc.log('\n'); pc.log('Properties that exists only in location:'); pc.log(comparedObj.onlyA); pc.log('\n'); pc.log('Properties that exists only in url:'); pc.log(comparedObj.onlyB); pc.log('\n');

Location能用作URL的构造参数,是因为前者实现了一个toString方法,该方法返回一个表示请求地址的字符串:

pc.log(window.location.toString());

递归构建URL

利用URL构造函数中可以访问上级目录、且可以同时指定基础路径的特点,我们可以编写一个递归函数,在每次遍历中,只需将当前工作路径设置为上一次遍历时的父路径即可。

let currURL = window.location; pc.log(`current path: ${currURL.pathname}`); let fileName = 'serial-parts-struct.json'; async function findInParent() { let serialURL = new URL(`../${fileName}`, currURL); let response = await fetch(serialURL); if (response.ok) { pc.log(`find: ${serialURL.pathname}`); return await response.json(); } if (serialURL.pathname === `/${fileName}`) { return; } else { currURL = serialURL; return findInParent(); } } let jsonFile = await findInParent();

这种技巧在自动构建多层级的动态网页时比较实用。

但这种方法无法捕获Response抛出的404异常,且在一些浏览器中,无法捕获的异常可能会影响后续代码。因此这种方式只适合应用于特定场合且需经调试。

而如果要查找的文件位置有默认的约定,如总存在于二级子路径下面,则可通过正则表达式快速地加载。

let partStruct = await (async () => { let currURL = window.location; let fileName = 'serial-parts-struct.json'; let serialJSONLocation = /(^\/.+?\/.+?\/).+/.exec(currURL.pathname); return await fetch(`${serialJSONLocation[1]}${fileName}`) .then(response => response.json()); } )(); pc.log(partStruct);

本站的技术文档的结构与存储均大量借鉴了DocBook 5的众多长处,因此serial-parts-struct.json文件在本站中有举足轻重的作用,例如,若将基础篇中的概述调整至高级篇中,只需修改此文件即可。在用户浏览网页时,相应的JavaScript文件则依据此文件自动即时编排文章结构,自动生成左边、右边及下边的导航栏,以及正文中的章节目录编号,非常方便。

createObjectURL

URL的静态方法createObjectURL可根据一个Blob对象,创建一个URL,具体参见创建URL

参考资源

  1. URL Living Standard
  2. URL API