URL参数必须用encodeURIComponent()单独编码路径段和查询参数,禁用encodeURI();查询参数优先用URLSearchParams构建;路径模板应封装函数自动编码;服务端模板需显式URI编码而非仅HTML转义。

URL 模板里怎么安全插值参数
直接拼字符串最常见,也最容易出错——比如 user_id 是 123/abc,一拼就变成 /user/123/abc/profile,路由直接 404;或者 q=hello world 没编码,空格变 + 或直接截断。核心是:**参数必须经过 URI 编码,且不能破坏 URL 结构**。
- 用
encodeURIComponent()处理每个参数值,别用encodeURI()(它不编码/、?等,不适合单个参数) - 路径段(如
/users/{id}中的{id})和查询参数(?name=xxx)都要单独编码,不能对整个 URL 字符串调用一次编码 - 如果模板含固定路径斜杠(如
/api/v1/posts/{post_id}),确保post_id值本身不含非法字符,否则先校验或抛错,比静默失败更可控
用 URLSearchParams 构建查询参数最省心
手动拼 ?a=1&b=2 容易漏 &、多 =、搞混 ? 和 & 位置。浏览器原生 URLSearchParams 自动处理编码和连接逻辑,兼容性到 Chrome 49+/Firefox 29+,够用。
- 创建时传对象:
new URLSearchParams({ q: 'hello world', page: 2 })→q=hello%20world&page=2 - 追加参数用
.append(),避免重复键时用.set() - 最终用
.toString()拿字符串,直接拼到 URL 后面,不用自己加? - 注意:它不处理路径部分,只管
?后面的内容
模板字符串 + 函数封装,避免每次重复写编码逻辑
项目里 URL 模板一多,到处写 encodeURIComponent(x) 很累,还容易漏。不如封装一个简单函数,把模板和参数一起喂进去,自动完成替换和编码。
- 示例函数:
function urlTemplate(template, params) { return template.replace(/\{(\w+)\}/g, (_, key) => encodeURIComponent(params[key])); } - 调用:
urlTemplate('/user/{id}/posts', { id: '123/abc' })→/user/123%2Fabc/posts - 只匹配
{xxx}形式,不碰$xxx或:xxx,降低误替换风险 - 如果参数缺失,当前逻辑会替换成
undefined,建议加一层if (!(key in params)) throw new Error(...)
后端渲染模板(如 Jinja2、EJS)里别信默认转义
前端 JS 里你控制编码,但服务端模板常默认对变量做 HTML 转义(& → &),结果生成的 URL 里出现 &,浏览器当字面量解析,请求直接 400。
- Jinja2 用
{{ url|urlencode }},不是{{ url }} - EJS 用
,别用(它只取消 HTML 转义,不编码 URI) - Node.js 的
express+res.render()传入的参数仍是纯 JS 对象,编码动作仍在模板层,别在 JS 层提前编码再传进去,否则可能双重编码
实际写的时候,路径参数和查询参数的编码时机、范围、工具都不同,混用一套逻辑反而容易翻车。盯住「谁负责哪一段」「编码是否被模板引擎二次干扰」这两个点,基本不出大问题。

















