URL 处理
本教程共 76 篇 · 第 23 篇 · 更新于 2026-07-25 · 约 4 分钟阅读
23. URL 处理
本节目标:WHATWG URL API 解析和构造 URL,处理查询参数。
Web 开发里天天跟 URL 打交道:解析请求参数、拼接接口地址、校验跳转链接。Node.js 内置了 WHATWG URL 标准实现,和现代浏览器用的是同一套 API,学完这里前端后端通用。
旧版的 url.parse() 虽然还在,但已经打上 Legacy 标签,新代码别再用了。
23.1 解析 URL
const url = new URL('https://user:pass@api.example.com:8080/v1/users?id=123#profile');
console.log(url.protocol); // https:
console.log(url.username); // user
console.log(url.password); // pass
console.log(url.hostname); // api.example.com
console.log(url.host); // api.example.com:8080
console.log(url.port); // 8080
console.log(url.pathname); // /v1/users
console.log(url.search); // ?id=123
console.log(url.hash); // #profile
console.log(url.href); // 完整 URL
new URL() 解析失败会直接抛 TypeError,不用像 url.parse 那样检查返回值。
23.2 相对路径解析
URL 构造函数的第二个参数是 base URL,用来解析相对路径:
const base = 'https://example.com/blog/';
new URL('2024/hello.html', base).href;
// https://example.com/blog/2024/hello.html
new URL('/about', base).href;
// https://example.com/about
new URL('../contact', base).href;
// https://example.com/contact
拼接 URL 时比字符串拼接安全得多,会自动处理斜杠、编码等问题。
23.3 URLSearchParams:查询参数
URL 实例上的 searchParams 返回一个 URLSearchParams 对象,专门操作 ? 后面的键值对:
const url = new URL('https://api.example.com/search?q=nodejs&page=1');
const params = url.searchParams;
params.get('q'); // nodejs
params.get('page'); // 1
params.set('page', '2');
params.append('sort', 'desc');
params.delete('filter');
console.log(url.search); // ?q=nodejs&page=2&sort=desc
console.log(url.href); // 完整 URL 已更新
Note
URLSearchParams修改后会自动同步回父 URL 对象,不需要手动赋值。
独立使用
不依附于 URL 对象,直接操作查询字符串:
const params = new URLSearchParams('name=Alice&age=30');
params.append('city', 'Beijing');
console.log(params.toString()); // name=Alice&age=30&city=Beijing
// 遍历
for (const [key, value] of params) {
console.log(key, value);
}
// 转成普通对象(注意同名参数会丢失)
const obj = Object.fromEntries(params);
编码与解码
URLSearchParams 会自动对特殊字符做 encodeURIComponent 和 decodeURIComponent:
const params = new URLSearchParams();
params.set('name', '张三');
params.set('redirect', 'https://a.com?x=1');
console.log(params.toString());
// name=%E5%BC%A0%E4%B8%89&redirect=https%3A%2F%2Fa.com%3Fx%3D1
如果你需要更精细的控制(比如只编码部分字符),可以手动调用 encodeURIComponent。
23.4 路径拼接与文件 URL
Node.js 里经常要把文件路径转成 file:// 协议的 URL,比如动态 import() 时:
import { pathToFileURL } from 'node:url';
import { join } from 'node:path';
const filePath = join(process.cwd(), 'config.js');
const fileUrl = pathToFileURL(filePath);
console.log(fileUrl.href); // file:///C:/project/config.js (Windows)
// 用于动态 import
const mod = await import(fileUrl.href);
反过来,把 file:// URL 转回本地路径:
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
23.5 url.parse 的迁移提示
老项目里你可能还见到这种代码:
import url from 'node:url';
const parsed = url.parse('https://example.com/path?a=1');
console.log(parsed.query); // 'a=1'
迁移到 URL 很简单:
| 旧写法 | 新写法 |
|---|---|
url.parse(str).pathname | new URL(str).pathname |
url.parse(str).query | new URL(str).searchParams |
url.parse(str).host | new URL(str).host |
url.parse(str, true).query | Object.fromEntries(new URL(str).searchParams) |
唯一需要注意的是:url.parse 对格式错误的 URL 比较宽容,new URL() 更严格,非法格式会抛错。如果你的输入来源不可信,包一层 try/catch:
function safeParseURL(input) {
try {
return new URL(input);
} catch {
return null;
}
}
23.6 实战:构建安全的请求 URL
把本节内容串起来,写一个带签名参数的请求 URL 构建器:
import { createHash } from 'node:crypto';
function buildApiUrl(base, path, params, secret) {
const url = new URL(path, base);
// 填入业务参数
Object.entries(params).forEach(([k, v]) => {
url.searchParams.set(k, String(v));
});
// 加入时间戳
url.searchParams.set('t', String(Date.now()));
// 生成签名(实际项目用 HMAC,这里简化示例)
const signBase = url.searchParams.toString() + secret;
const sign = createHash('sha256').update(signBase).digest('hex');
url.searchParams.set('sign', sign);
return url.href;
}
const apiUrl = buildApiUrl(
'https://api.example.com',
'/v1/order',
{ userId: 10086, status: 'paid' },
'my-secret-key'
);
console.log(apiUrl);