跳到正文
DevTools / URL 与 HTML 编码

URL 与 HTML 编码

两套转义系统制造了比例高得离谱的 Web 缺陷。URL 编码决定查询参数里的 & 是数据还是分隔符;HTML 实体编码决定一个小于号是文本还是标签的开头。本工具同时处理两者,实时预览解码后的标记以便看到浏览器真正的渲染结果,并能识别大多数编码器会放过的不合法百分号序列。

完全在浏览器本地运行——不会上传任何内容。

结果
暂无内容

工作原理

百分号编码会把每个非保留字符的字节替换成百分号加两位大写十六进制。RFC 3986 把 ASCII 分成三类:非保留字符(A-Z、a-z、0-9、连字符、句点、下划线、波浪号)永不编码;保留字符(: / ? # [ ] @ ! $ 等)具有结构含义,只有作为数据使用时才编码;其余字符一律编码。空格是特例:在几乎所有上下文中 %20 都合法,而用加号表示空格只在 application/x-www-form-urlencoded 请求体中才是正确的。

encodeURI 与 encodeURIComponent 不可互换,混淆二者是经典错误。作为完整 URI 编码时,https://example.com/a b 会保留协议、斜杠和问号,变成 https://example.com/a%20b;作为单个组件编码时,同样的输入会变成 https%3A%2F%2Fexample.com%2Fa%20b,因为此时斜杠和冒号都是数据。如果服务端收到的 URL 里出现 %3A%2F%2F,说明客户端调用了错误的函数。

HTML 实体编码是完全不同的问题。在 HTML 中,&、<、>、引号和撇号都是结构性字符:未转义的 < 会开启一个标签,未转义的 & 会开始一个实体引用,属性内未转义的引号会提前结束属性。转义它们就把标记变成了惰性文本。这正是阻止跨站脚本的机制——包含 script 标签的评论会被当作字符显示而非执行——也是为什么所有模板引擎默认转义,而绕过该默认值的“原始 HTML”辅助函数常常成为漏洞源头。

解码一侧比多数实现更严格。百分号后面若不是两个十六进制数字,就不是可解码序列,静默放过只会掩盖数据损坏,因此本工具会报出位置。HTML 实体会解析完整的命名集合以及十进制和十六进制数字引用,所以 &amp;、&#38; 和 &#x26; 都解码为同一个 &。工具还会检验往返一致性,让你确认“先解码再编码”能逐字节还原原始输入。

常见应用场景

  • 手工构造查询字符串,对包含空格、& 或中文的搜索词做编码。
  • 查看被编码了两次的跟踪链接,弄清真实的目标地址。
  • 把用户提供的文本转义后再粘进 HTML 模板或邮件正文。
  • 解码 OAuth 的 redirect_uri 参数,找出授权服务器拒绝它的原因。
  • 把含有嵌套 URL 的参数编码成回调或 Webhook 配置所需的形式。
  • 确认即将写入属性中的值无法突破引号边界。

最后更新: 2026-10-14

常见问题解答

空格应该写成 %20 还是 +?

取决于上下文。在路径、用于路由的查询字符串或任何 RFC 3986 语境中,空格是 %20,加号在那里就是字面的加号。在 application/x-www-form-urlencoded 的表单提交中,加号表示空格,此时写 %20 虽然也能工作但不常见。拿不准时用 %20:它在任何地方都正确,而 + 只在表单体中正确。

HTML 转义为什么能防住 XSS?

XSS 的本质是攻击者提供的文本被当作标记解析,而不是被当作字符显示。转义把五个结构性字符——&、<、>、双引号和撇号——换成实体引用,于是评论里的 script 标签变成一串可见字符而非可执行元素。但它并不足够:转义必须匹配上下文,放进 JavaScript 字符串或 URL 属性里的值与放进元素内容里的值需要不同的处理方式。

为什么我的 URL 被编码了两次?

几乎总是因为已经把编码后的字符串又交给编码器处理了一次,于是百分号本身变成了 %25。包含 %2520 的 URL 被编码了两次——外层解一次得到 %20,再解一次才是空格。双重编码常见于重定向链,也常见于代理对收到的 URL 重新编码的系统,所以当参数看起来不对时,先解一层再看是否还残留第二层。

把生产环境的 URL 粘进来安全吗?

安全。所有转换都在浏览器内的 JavaScript 中完成,不通过网络发送任何内容——“编码”按钮背后没有 API 调用。但要记住,URL 本身可能携带密钥,例如 API key、签名 token 或会话标识,复制结果时它们会进入浏览器历史和剪贴板。无论用什么工具查看,签名 URL 都应被当作凭证对待。

相关工具