部落格 • 分享機制
用 URL Hash 分享 JSON:不上傳伺服器的原理、限制與用法
同事說「你那邊 JSON 一格式化就對,我這邊報錯」。把文件傳來傳去很煩,截圖又沒辦法繼續改。
URL Hash 分享把目前工具和輸入寫進網址列的#後面。對方打開同一條鏈接,瀏覽器在本地還原左右欄;普通頁面請求不會把這份資料發給伺服器。
這和「貼到某個線上格式化網站再點分享」不是一回事。後者通常會先把原文 POST 到別人的後端,再給你一個短鏈。 Hash 分享沒有這一步。
本文將說明:
- URL Hash 為什麼通常不會出現在伺服器日誌裡
- DevBox 的
#tool=…&data=…怎麼編碼 - 為什麼 Base64 不是加密
- 連結會膨脹多少、哪些軟體會截斷
- 什麼時候該用分享,什麼時候必須停手
先記住這一點:Hash 能用,是因為瀏覽器預設不把#後面發給伺服器。但這既不是加密,也擋不住聊天軟體把連結截斷。以下按「原理 → 編碼 → 長度 → 邊界」把這件事拆開。
URL Hash 分享是什麼
完整 URL 可以拆成兩段:伺服器會看到的部分,和只留在瀏覽器裡的部分。
請求發給伺服器 fragment / Hash(只留在瀏覽器)
DevBox 的「分享」做的是:把目前工具 id 和左側輸入編碼進 Hash,再把整段location.href複製到剪貼簿。對方打開後,頁面腳本讀location.hash,在他自己的瀏覽器裡還原工具和文字。
-
1
你在瀏覽器裡點「分享」
輸入先轉成 UTF-8,再編成 Base64,寫成
#tool=&data=。 -
2
把完整 URL 發給同事
對方打開同一網站後,頁面腳本讀
location.hash。 -
3
在對方瀏覽器裡還原
本地格式化、校驗或 Diff。伺服器只收到頁面本身,沒有這份 JSON。
這和把 JSON 處理放在瀏覽器裡是同一原則:計算發生在本地,分享也不經過我們的資料庫。隱私邊界寫在隱私權聲明第 3 節。
為什麼 Hash 不會上傳到伺服器
Fragment 不會進入 HTTP 請求
按MDN 對 URL.hash 的說明和WHATWG URL 標準裡的 fragment,#之後是 fragment identifier。瀏覽器導航時,HTTP 請求的 path / query 不包含這段。
所以訪問日誌里通常只有:
GET /json/format.html HTTP/1.1
而不是:
GET /json/format.html#data=……
這也是為什麼 Hash 適合「我不想讓網站存一份我的貼」,卻不適合當保密通道:資料仍在完整 URL 裡,只是預設不走這一跳網路。
和 Query String 的差別
| 寫法 | 例子 | 伺服器看不看得到 | 適合做什麼 |
|---|---|---|---|
| Query | ?tool=json-format&data=… |
會。出現在請求行、反向代理程式和 CDN 日誌裡 | 需要服務端讀的參數 |
| Hash | #tool=json-format&data=… |
普通頁面請求不會帶上 | 只給前端腳本用的狀態 |
如果有人把同樣的 Base64 放到?後面,效果看起來一樣,資料卻已經進了伺服器日誌。 DevBox 只寫 Hash,就是為了避開這一層。
另外:Referer 通常也不帶 fragment。你從分享頁點到外鏈,對方網站一般拿不到 Hash 裡的 JSON。這是瀏覽器預設行為,不是我們額外做的加密。
DevBox 的分享連結長什麼樣
點「分享」後,Hash 是一組URLSearchParams:
#tool=json-format&data=<Base64>
tool
目前工具 id。打開連結後會切到對應工作區,而不是一律落到「JSON 格式化」。常見值包括json-format、json-validate、json5、json-path、json-diff。
只切換工具、不點分享時,網址列會更新成#tool=…,不含 data。這是為了記住你在用哪個工具,不會把編輯器裡的內容寫進歷史記錄。
data
左側輸入的 UTF-8 文本,再做 Base64。實現上等價於:
btoa(unescape(encodeURIComponent(input)))
先encodeURIComponent是為了讓中文和 Emoji 能過btoa。還原時走相反路徑。這和 MDN 討論的Unicode 字串的 Base64 編碼是同一類問題。
編碼不是加密
Base64 的目的在於「任意位元組都能放進 URL」,不是「只有受信方能讀」。任何人拿到鏈接,都可以在控制台還原:
const data = new URLSearchParams(location.hash.slice(1)).get("data");
decodeURIComponent(escape(atob(data)));
也可以把data=後面的字串丟進本站的Base64 解碼。沒有口令,沒有一次性鏈接,也沒有過期時間。
一個完整範例
假設你在「JSON 格式化」裡輸入:
{
"name": "Ada",
"role": "dev"
}
壓縮成一行後是 27 位元組:
{"name":"Ada","role":"dev"}
UTF-8 → Base64 得到 36 個 ASCII 字元(這段裡面沒有+ / /,放進 URL 時不會再被百分號編碼延長):
eyJuYW1lIjoiQWRhIiwicm9sZSI6ImRldiJ9
完整 Hash:
#tool=json-format&data=eyJuYW1lIjoiQWRhIiwicm9sZSI6ImRldiJ9
對方打開後看到同一段 JSON,可以繼續格式化、做JSONPath 抽取,或和自己的回應做 Diff。若原文其實是附註解的配置,應改用JSON5 解析再分享輸出,而不是把無法JSON.parse的文字直接丟給對方。
含中文時量更明顯。例如{"msg":"格式化后两边一致"}是 34 位元組 UTF-8,Base64 後 48 字元;其中的/和=再被 URL 編碼,參數值會變成 54 字元。
連結會變多長
Hash 分享的硬限制不是「伺服器上傳上限」,而是整段 URL 還能無法完整送達對方瀏覽器。
對一段近似純 ASCII 的 JSON,實測數量級如下(含tool=json-format&data=的膨脹後長度):
| 原文大約 | 編碼後 Hash 大約 | 經驗限制 |
|---|---|---|
| 200 B | 330 字符 | 聊天軟體幾乎都能完整送達 |
| 1 KB | 1.4 KB | 多數 IM 沒問題,仍建議自己點開確認 |
| 8 KB | 11 KB | 瀏覽器通常能開啟;部分客戶端會截斷 |
| 32 KB | 44 KB | 不要指望微信 / 郵件原文轉寄還能用 |
Chrome 能消化很長的網址欄,但中間還有一層:IM、郵件、短鏈服務、二維碼。它們各自有更短的上限,而且很少告訴你「我把尾巴切掉了」。所以流程應是:
-
1
點「分享」
複製完整地址,不要只抄
#後面一截。 -
2
先在本機新標籤打開
確認工具和輸入都在,再發給同事。
整份存取日誌、數兆的匯出文件,請本機貼上或點「下載」。 Hash 分享解決的是「復現一小段輸入」,不是當網盤。
Hash 分享和其他方式比什麼
| 方式 | 數據去哪 | 對方怎麼接著乾 | 適合 | 不適合 |
|---|---|---|---|---|
| URL Hash | 停在雙方網址列 | 打開同一站點即可繼續處理 | 小段 JSON、復現報錯 | 金鑰、超大文件 |
| 聊天原文 | 聊天伺服器 | 再複製一次 | 幾行配置 | 進永久會話記錄的內部數據 |
| 截圖 | 圖片 | 只能看,不能 parse | 讲结构 | 還要繼續格式化 / Diff |
| 附件 / 网盘 | 第三方存储 | 下载后再贴 | 大文件 | 想避免多一份副本 |
| 在线 Paste | 别人的后端 | 打开短链 | 需要公開、長期存放 | 任何不該離開本機的內容 |
團隊裡若已經有內網 paste 或工單附件,大段日誌走原有通道更穩。 Hash 的价值是:同一條連結同時帶著「用哪個工具」和「輸入是什麼」,對方不用猜你點的是格式化還是校驗。
使用時必須記住的邊界
- 链接等于明文。能打開頁面的人就能還原內容。不要分享金鑰、生產 Token、客戶名單或未公開介面。
- 發出去之前先自己點開。聊天軟體截斷超長 URL 時,對方會開啟一個殘缺 Hash,表現為空白輸入或解碼失敗。
- 對方必須能打開同一個 DevBox 站點。Hash 不能脫離頁面單獨解析;把
#後面一段丟進記事本沒有用。 - 瀏覽器歷史記錄會留下完整地址。本機歷史、同步的帳號、螢幕分享都能看到。不點分享、只切換工具時,Hash 裡沒有 data,就是為了少寫一份。
- 擴展和調試工具可能讀到
location.href。本地運算降低的是「我們站點存一份」的風險,不是「這台電腦上誰都看不見」。 - 「從 URL 拉取」是另一條路。當工作區填寫遠端位址並點選「拉取」時,瀏覽器會向那個位址發送請求。分享 Hash 裡如果帶了
url=,打開的人也會發起這次請求。只信你自己核對過的來源。
涉及真實隱私時,用離線或內網工具。這和「網站有沒有登入框」無關。
常見問題
URL Hash 分享是什麼?
把目前工具和輸入編碼進網址列#後面。對方打開同一網站的同一條鏈接,瀏覽器在本地還原內容,而不把這份資料作為頁面請求發給伺服器。
Hash 裡的數據伺服器能看到嗎?
普通頁面請求不會把 fragment 發給伺服器,訪問日誌裡通常只有路徑。但這不等於保密:拿到完整連結的人都能解碼。
編碼和加密有什麼不同?
編碼(這裡是 Base64)保證文字能放進 URL,任何人都能反向還原。加密需要金鑰,沒有金鑰就不能讀。 DevBox 分享做的是前者。
Hash 分享可以用於金鑰或 Token 嗎?
不可以。連結一旦發出就無法收回,歷史記錄裡也還在。密鑰請走你們團隊的金鑰管理系統,不要進任何網頁網址列。
對方打開是空白的?
先检查 URL 是否在data=中間被截斷;再確認打開的是同一個 DevBox 站點,而不是只複製了#後面一截。超大文本请改用本机粘贴。
和 JSON 格式化、校验是什么关系?
分享只負責「原樣帶走當前輸入和工具」。格式化、文法校驗、JSON5、JSONPath、Diff 仍在對方瀏覽器裡本地執行。需要先看结构,用JSON 格式化;需要定位Unexpected token,用校驗或JSON5。
總結
URL Hash 分享本质上是:
本機工具狀態 + 可逆編碼 + 瀏覽器 fragment 不隨要求上傳。
它適合複現一小段 JSON 或配置,不適合當網盤,更不適合傳秘密。用對了,你和同事對著同一左右欄說話;用錯了,等於把明文貼進一條誰都能打開的地址。