本文暫無當前語言版本,以下為 zh-CN 原文。

URL 解析与编码完全指南:从结构拆解到安全处理的全流程实战

加密編碼(更新於 2026年6月2日)

URL 的完整结构

https://user:pass@example.com:8080/path/to/page?name=value&age=25#section
  │       │     │    │          │  │   │            │                │
  scheme  user  pass  host      port path           query            fragment
组成部分 示例 说明
scheme https 协议
userinfo user:pass 认证信息(已很少使用)
host example.com 域名或 IP
port 8080 端口号(默认 80/443)
path /path/to/page 路径
query ?name=value&age=25 查询参数
fragment #section 锚点(不发送到服务器)

使用 URL API 解析

基础解析

const url = new URL('https://example.com:8080/path?q=test#section');

url.protocol  // "https:"
url.hostname  // "example.com"
url.port      // "8080"
url.pathname  // "/path"
url.search    // "?q=test"
url.hash      // "#section"
url.origin    // "https://example.com:8080"
url.href      // 完整 URL

解析查询参数

const url = new URL('https://example.com/api?name=Alice&age=25&tags=js&tags=css');

// URLSearchParams
url.searchParams.get('name')     // "Alice"
url.searchParams.get('age')      // "25"
url.searchParams.getAll('tags')  // ["js", "css"]
url.searchParams.has('name')     // true
url.searchParams.delete('age')

// 遍历
for (const [key, value] of url.searchParams) {
  console.log(`${key} = ${value}`);
}

修改 URL

const url = new URL('https://example.com/page');

url.pathname = '/new-page';
url.searchParams.set('sort', 'desc');
url.searchParams.append('filter', 'active');
url.hash = '#top';

console.log(url.toString());
// "https://example.com/new-page?sort=desc&filter=active#top"

URL 编码规则

为什么需要编码?

URL 只允许 ASCII 字符,其他字符必须编码:

原始:https://example.com/search?q=你好 世界
编码:https://example.com/search?q=%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C

encodeURI vs encodeURIComponent

函数 编码范围 用途
encodeURI 保留 URL 结构字符(:/?#[]@!$&'()*+,;= 编码完整 URL
encodeURIComponent 编码所有非 ASCII + 保留字符 编码查询参数值
const url = 'https://example.com/path?name=你好&redirect=/home';

// encodeURI:保留 URL 结构
encodeURI(url);
// "https://example.com/path?name=%E4%BD%A0%E5%A5%BD&redirect=/home"

// encodeURIComponent:编码所有特殊字符
encodeURIComponent(url);
// "https%3A%2F%2Fexample.com%2Fpath%3Fname%3D%E4%BD%A0%E5%A5%BD%26redirect%3D%2Fhome"

// ✅ 正确用法:参数值用 encodeURIComponent
const name = '你好 世界';
const redirect = '/home';
const fullUrl = `https://example.com/path?name=${encodeURIComponent(name)}&redirect=${encodeURIComponent(redirect)}`;

常见编码对照

字符 编码 说明
空格 %20 URL 中不用 +
+ %2B 查询参数中 + 会被解码为空格
& %26 查询参数分隔符
= %3D 键值分隔符
# %23 锚点标识符
% %25 编码前缀本身
中文 %E4%BD%A0 UTF-8 三字节编码

使用工具库编解码 URL

  1. 打开 URL 编解码工具
  2. 在输入框粘贴 URL 或文本
  3. 点击"编码"或"解码"
  4. 查看结果

URL 安全处理

1. 防止 URL 注入

// ❌ 危险:直接拼接用户输入
const url = `/api/users/${userId}`;

// ✅ 安全:验证 + 编码
function buildUserUrl(userId) {
  if (!/^\d+$/.test(userId)) {
    throw new Error('Invalid user ID');
  }
  return `/api/users/${encodeURIComponent(userId)}`;
}

2. 防止开放重定向

// ❌ 危险:用户可以指定任意 redirect URL
app.get('/login', (req, res) => {
  res.redirect(req.query.redirect);
});

// ✅ 安全:白名单验证
function safeRedirect(url, allowedHosts) {
  try {
    const parsed = new URL(url, 'https://example.com');
    if (allowedHosts.includes(parsed.hostname)) {
      return url;
    }
  } catch {
    // 无效 URL
  }
  return '/'; // 降级到首页
}

3. 防止 XSS via URL

// ❌ 危险:javascript: 协议
const url = 'javascript:alert(document.cookie)';

// ✅ 安全:只允许 http/https 协议
function sanitizeUrl(url) {
  try {
    const parsed = new URL(url);
    if (['http:', 'https:'].includes(parsed.protocol)) {
      return url;
    }
  } catch {
    // 无效 URL
  }
  return 'about:blank';
}

URLPattern API(新标准)

// 路由匹配
const pattern = new URLPattern({ pathname: '/api/users/:id' });

const result = pattern.exec('https://example.com/api/users/123');
if (result) {
  console.log(result.pathname.groups.id); // "123"
}

// 更复杂的模式
const apiPattern = new URLPattern({
  protocol: 'https',
  hostname: ':env.example.com',
  pathname: '/api/:version/:resource/:id?',
});

const match = apiPattern.exec('https://prod.example.com/api/v2/users/456');
match.hostname.groups.env      // "prod"
match.pathname.groups.version  // "v2"
match.pathname.groups.resource // "users"
match.pathname.groups.id       // "456"

查询参数构建最佳实践

使用 URLSearchParams

// ✅ 推荐:使用 URLSearchParams
const params = new URLSearchParams({
  q: '搜索关键词',
  sort: 'desc',
  page: '1',
  limit: '20',
});

params.append('tags', 'javascript');
params.append('tags', 'css');

const url = `https://api.example.com/search?${params}`;
// "https://api.example.com/search?q=...&sort=desc&page=1&limit=20&tags=javascript&tags=css"

数组参数的常见约定

约定 示例 服务端框架
重复键 ?tags=js&tags=css Express, Koa
括号后缀 ?tags[]=js&tags[]=css PHP, Rails
下标 ?tags[0]=js&tags[1]=css PHP
逗号分隔 ?tags=js,css 自定义

常见问题

为什么 URL 中的空格有时是 %20 有时是 +

  • URL 路径中:空格 = %20(标准)
  • 查询参数中:空格 = +%20+ 是 application/x-www-form-urlencoded 约定)
  • 推荐:统一用 %20,避免歧义

URL 有最大长度限制吗?

场景 限制
Chrome URL 栏 2MB
Firefox URL 栏 无限制
IE URL 栏 2083 字符
HTTP GET 请求 服务器决定(通常 8KB)
安全上限 2048 字符(兼容所有浏览器)

超过 2048 字符的参数应改用 POST 请求。


总结

URL 是 Web 的基石,理解其结构、编码规则和安全处理是每个开发者的基本功。核心要点:参数值用 encodeURIComponent 编码,验证协议防止 XSS,白名单验证防止开放重定向。工具库的 URL 编解码工具 帮你快速处理 URL 编码问题。

#URL解析#URL编码#查询参数#Web开发#教程