Skip to content

url path 是否可以包含 # ?

结论先行:

URL 的 path 中可以包含 ?(需编码)不能包含未编码的 #

下面把规则、原因和实际开发中的坑一次讲清楚。


1️⃣ URL 的标准结构(RFC 3986)

scheme://authority/path?query#fragment
  • path:路径
  • ?query 的分隔符
  • #fragment 的分隔符(锚点)

👉 也就是说: ?# 在 URL 里是“结构字符”,不是普通字符。


2️⃣ # 能不能出现在 path 中?

❌ 不可以(除非编码)

  • # 一旦出现,后面的内容都会被浏览器当成 fragment
  • fragment 不会发送给服务器
txt
https://example.com/a/b#c/d

浏览器真正发给服务器的是:

txt
GET /a/b HTTP/1.1

👉 #c/d 完全不会进入 path

✅ 正确做法(想当普通字符)

txt
# → %23
txt
https://example.com/a/b%23c/d

服务器接收到的 path 是:

txt
/a/b#c/d

3️⃣ ? 能不能出现在 path 中?

⚠️ 原则上:不能直接用,但可以编码

  • 第一个未编码的 ? 会被解析为 query 起始符
  • 后续的 ? 在 query 中是普通字符
txt
https://example.com/a/b?c/d

path 实际是:

txt
/a/b

query 是:

txt
c/d

✅ 想把 ? 当作 path 的一部分

txt
? → %3F
txt
https://example.com/a/b%3Fc/d

服务器看到的 path:

txt
/a/b?c/d

4️⃣ 总结对照表

字符未编码时的作用是否能出现在 path正确做法
#fragment 分隔符❌ 不能编码成 %23
?query 分隔符❌ 不能编码成 %3F
%23#✅ 可以
%3F?✅ 可以

5️⃣ JS / 前端开发中的常见坑

❌ 错误示例(后端永远收不到 #

js
fetch('/api/file/a#b')

后端收到的其实是:

/api/file/a

✅ 正确示例

js
const path = encodeURIComponent('a#b?c')
fetch('/api/file/' + path)

后端收到:

/api/file/a#b?c

6️⃣ encodeURI vs encodeURIComponent(很关键)

方法是否编码 ?是否编码 #使用场景
encodeURI❌ 不编码❌ 不编码整个 URL
encodeURIComponent✅ 编码✅ 编码path / query 的值

👉 结论

path 的动态片段,永远用 encodeURIComponent


7️⃣ 一句话结论

URL path 中不能直接包含 #?, 想用就必须百分号编码(%23%3F

encodeURI vs encodeURIComponent

场景用哪个
整个 URLencodeURI
path 变量encodeURIComponent
query valueencodeURIComponent