隆重推出 WHATWG URL API,已在 Node.js 8.0 中正式实现!
你好。
我是Mandai,负责Wild 开发团队。
不久前,Node.js 8.0.0 于 2017 年 5 月 30 日发布。
从这个版本开始,捆绑了 npm 5.0.0 版本,并且围绕缓存的代码已被重写,似乎速度更快。
还发布了一条与过去版本进行速度比较的推文,在本例中,安装完成速度似乎是之前版本的 1/5。
随着#npm5即将发布,我想我应该更新这些基准。
这是我正在处理的 npm5 代码,与流行存储库上的npm@4.6.1pic.twitter.com/KWPfbpE46p
— ✨11x 同性恋 Kat✨ (@maybekatz) 2017 年 5 月 19 日
目前V8引擎的版本是5.8版本,但似乎与V8 5.9和V8 6.0兼容,并且未来的版本预计会通过升级版本的V8引擎变得更快。 → Node.js 8.0 发布。 npm 5.0 捆绑包,包含 Node.js API,官方支持 WHATWG URL 解析器等 - Publickey
这次我想看一下 WHATWG URL API,它在 Node.js 8.0 中正式实现。
什么是WG URL API! ?
实际上,WHATWG URL API 从 Node.js 7 系列开始就已经存在,但在 8.0.0 才成为正式版本。
很多人可能已经使用过它,但由于它处于“实验”地位,他们可能对在生产环境中使用它有点犹豫。
该 API 旨在标准化 URL 解析,并作为传统 URL 模块的扩展提供。
1 | const URL = require( 'url' ).URL; const BeyondUrl = new URL( 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ); // 结果URL { href: 'http://www.beyondjapan.com/?abc=123&xyz=999#first' , 来源: 'http://www.beyondjapan.com' , 协议: 'http:' , 用户名: '' ,密码: '' ,主机: 'www.beyondjapan.com' ,主机名: 'www.beyondjapan.com' ,端口: '' ,路径名: '/' ,搜索: '?abc=123&xyz=999' ,searchParams: URLSearchParams { 'abc' => '123' , 'xyz' => '999' }, 哈希值: '#first' } |
当然你也可以使用URL模块,感觉和以前一样。
1 | const url = require( 'url' ); const BeyondUrl = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; console.log(url.parse(beyondUrl)); { 协议: 'http:' ,斜杠: true ,身份验证: null ,主机: 'www.beyondjapan.com' ,端口: null ,主机名: 'www.beyondjapan.com' ,哈希: '#first' ,搜索: ' ?abc=123&xyz=999' ,查询: 'abc=123&xyz=999' ,路径名: '/' ,路径: '/?abc=123&xyz=999' ,href: 'http://www.beyondjapan.com/? abc=123&xyz=999#第一' } |
令人困惑的是,只有对象名称略有不同,但输出对象的内容也略有不同。
在 WHATWG URL API 的响应中,使用键 searchParams 解析并返回查询字符串很方便。
仅此一点就让您想使用它。
URL 对象的行为
从 WHATWG API 返回的 URL 对象也可以访问每个数据。
1 | const u = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; const URL = require( 'url' ).URL; const BeyondUrl = new URL(u); .hostname); // 结果 www.beyondjapan.com |
尝试使用不同的主机名。
1 | const u = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; const URL = require( 'url' ).URL; const BeyondUrl = new URL(u); example.com '; console.log(beyondUrl); // 结果 URL { href: ' http://example.com/?abc=123&xyz=999#first ', origin: ' http://example.com ',协议:' http: ',用户名:' ',密码:' ',主机:' example.com ',主机名:' example.com ',端口:' ',路径名:' / ',搜索:' ?abc= 123&xyz=999 ', searchParams: URLSearchParams { ' abc ' => ' 123 ', ' xyz ' => ' 999 ' }, 哈希: ' #first' } |
仅识别并重写主机名,因此如果执行以下操作,则仅更改主机名。
1 | const u = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; const URL = require( 'url' ).URL; const BeyondUrl = new URL(u); example.com:443 '; // 尝试添加端口号 console.log(beyondUrl); // 结果 URL { href: ' http://example.com/?abc=123&xyz=999#first ', origin: ' http://example.com ', 协议: ' http: ', // 不变 用户名: ' ', 密码: ' ', 主机: ' example.com ', 主机名: ' example.com ', 端口: ' ', // 不变的路径名: ' / ', search: ' ?abc=123&xyz=999 ', searchParams: URLSearchParams { ' abc ' => ' 123 ', ' xyz ' => ' 999 ' }, hash: ' #first' } |
如果要更改端口号,需要正确更改端口号。
1 | const u = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; const URL = require( 'url' ).URL; const BeyondUrl = 新 URL(u); ; console.log(beyondUrl); // 结果 URL { href: 'http://www.beyondjapan.com:443/?abc=123&xyz=999#first' , origin: 'http://www.beyondjapan.com :443' , 协议: 'http:' , // 不变 用户名: '' , 密码: '' , 主机: 'www.beyondjapan.com:443' , 主机名: 'www.beyondjapan.com' , 端口: ' 443 ' , 路径名: '/' , 搜索: '?abc=123&xyz=999' , searchParams: URLSearchParams { 'abc' => '123' , 'xyz' => '999' }, 哈希: '#first' } |
但更换主机后似乎就不是这样了。
1 | const u = 'http://www.beyondjapan.com/?abc=123&xyz=999#first' ; const URL = require( 'url' ).URL; const BeyondUrl = new URL(u); example.com:443 '; console.log(beyondUrl); // 结果 URL { href: ' http://example.com:443/?abc=123&xyz=999#first ', origin: ' http://example .com:443 ', protocol: ' http: ', // 未更改 username: ' ', 密码: ' ', host: ' example.com:443 ', // 已更改 hostname: ' example.com ', // 已更改port: ' 443 ', // 更改路径名: ' / ', search: ' ?abc=123&xyz=999 ', searchParams: URLSearchParams { ' abc ' => ' 123 ', ' xyz ' => ' 999 ' }, hash : ' #第一的' } |
URLSearchParams 类
前面我们研究了 URL 对象的行为,但现在让我们看看从 URL.searchParams 获取的 URLSearchParams 类。
该对象是 Node.js 7 系列中实现的一个类,用于解析查询字符串并提供 getters/setters。
官方文档将其与querystring模块进行了比较,但似乎URLSearchParams类没有querystring模块那么灵活,所以这并不意味着querystring模块是不必要的。
URLSearchParams 类作为 URL 模块中的类提供,因此也可以独立使用。
因此,它是一个强大的类,不仅可以用于分析,还可以用于生成。
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const qsObject = { abc:123, xyz:456, aaa:789 }; , 123], [ 'xyz' , 456], [ 'aaa' , 789], ]; const qsMap = new Map(); qsMap.set( 'abc' , 123); ); qsMap.set( 'aaa' , 789); 函数* qsGenerator(){ 产量 [ 'abc' , 123]; 产量 [ 'aaa' , 789]; new URLSearchParams(qs); // 即使是常规查询字符串格式 const params2 = new URLSearchParams(qsObject); // 即使是常规对象 const params3 = new URLSearchParams(qsIterable); // 即使是迭代器 const params4 = new URLSearchParams (qsMap) ); // 也在 Map 对象中 const params5 = new URLSearchParams(qsGenerator()); // 即使在生成器中 console.log(params2); (params4 ); console.log(params5); // 结果 URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } |
她是一个挑剔的孩子,什么东西都会吃,包括对象、数组、地图对象和生成器。
创建的 URLSearchParams 对象有多种方法。
追加以添加
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); params.append( 'bbb' , 963); .toString()) // 结果 // abc=123&xyz=456&aaa=789&bbb=963 |
删除
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); ()); // 结果 // abc=123&xyz=456&aaa=789 |
返回迭代器的条目
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); for ( let v of params.entries()) console.log(v ); // 结果 /* [ 'abc', '123' ] [ 'xyz', '456' ] [ 'aaa', '789' ] */ |
forEach for all 循环
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); params.forEach((value, key, p) => { console. log(value, key, p); }) // 结果 /* 123 abc URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } 456 xyz URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } 789 aaa URLSearchParams { 'abc' => '123', 'xyz' => '456', 'aaa' => '789' } */ |
get 返回参数键的值
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); //结果 // 123 |
getAll 返回参数键的所有值
由于我们正在讨论它与 get 的不同之处,因此我创建了两个示例。
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs) console.log(params.getAll( 'abc' )); // [ '一二三' ] |
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789&abc=777' ; const params = new URLSearchParams(qs); / 结果 // [ '123', '777' ] |
URLSearchParams 对象允许重复键,因此提供了 getAll 方法。
顺便说一句,在 get 方法的情况下,规范是返回重复键中第一个注册的键,因此该值可能只能在 getAll 或循环内访问。
检查是否存在
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); //结果 // 正确 |
键返回键的迭代器
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); for ( let k of params.keys()) console.log(k ); // 结果 /* abc xyz aaa */ |
设置为覆盖
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); params.set( 'vvv' , 247); .toString()); // 结果 // abc=123&xyz=456&aaa=789&vvv=247 params.set('vvv', 247); console.log(params.toString()); =456&aaa=789&vvv=247 |
如果对应的key不存在,则执行相当于append的动作,如果key存在,则覆盖key的内容。
如果存在多个键,则似乎将它们全部删除后追加。
1 | const qs = 'a=1&a=2&a=3' ; const params = new URLSearchParams(qs); // 此时 // a=1&a=2&a=3 params.set ('a', 4); console.log(params.toString()); // 结果 // a=4 |
破坏性排序
按名称对对象的内容进行排序。
看来逆向排序是不可能的。
请注意,它不会返回重新排列对象的 URLSearchParams 对象,而是重新排列执行对象的顺序(尽管顺序不是您真正关心的)。
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); ; console.log(params.toString()); // 结果 // 执行前 // abc=123&xyz=456&aaa=789&vvv=247 // 执行后 // aaa=789&abc=123&vvv=247&xyz=456 |
值返回值的迭代器
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); for ( let v of params.values()) console.log(v ); // 结果 /* 789 123 247 456 */ |
URLSearchParams 对象本身是可迭代的
1 | const {URLSearchParams} = require( 'url' ); const qs = 'abc=123&xyz=456&aaa=789' ; const params = new URLSearchParams(qs); for (const [k, v] of params) console.log(k , v); // 结果 /* aaa 789 abc 123 vvv 247 xyz 456 */ |
概括
我总结了WHATWG URL API和URLSearchParams,它们在以后的URL解析中将发挥重要作用。希望你已经理解了。
围绕查询字符串的实现虽然非常麻烦,但似乎正在取得进展。
就是这样。