Revision history and IPFS entry, back to latest
Benjamin
IPFS What is this

Content Hash

踩雷-網址參數編碼、網址解析邏輯

Benjamin
·
·

幾天前上班時和同伴討論一個遇到的問題:

他要在一個導向到新增資料的頁面之前插個檢查的步驟,因此要再檢查的步驟指定導向的連結。

原本的api功能根據傳來的資料資料其ID存在與否來判斷是更新還是新增,所以這部分也要寫在「導向的連結」內。

列出來大概像這樣:

檢查的步驟: /chkActiveProcess
導向的頁面: /insertForm?itemId=12345

但是有種情況是使用者要新增一筆資料,其內容複製於現有的某筆資料,因此同伴做了這樣的改動:

檢查的步驟: /chkActiveProcess
導向的頁面: /insertForm?itemId=12345&isNewItem=yes

使用一個新的參數判斷這種情況,然後問題就發生了。

重導向之後顯示的連結,不管怎麼試都看不到isNewItem=yes的部分。


這邊插播補充一下網址解析的小知識,一個網址當中夾帶的資訊包含:
要用什麼連線方式、連到哪台主機的名稱/座標、路徑、以及參數。

舉個例子,

http://example.com/add?a=1&b=2

打好連結按下enter時會由左到右解析出如上述的連線必要資訊

首先, http 是一種連線方式,其他還有https、ftp等姑且不談,後面固定接「://」的文字;

接著 example.com 是連線主機的名稱,從「://」開始到下一個「/」前結束;

路徑 /add 就像是給這網頁的指令,要執行什麼功能,如果路徑是空的視同訪問根目錄,匹配到「?」之前,如果沒有「?」就表示沒有參數;

最後是「?」之後,以「參數名=值」的形式傳遞,多個參數間以「&」分隔,因此列出參數:

a -> 1
b -> 2

回到正題,同伴使用nodejs,部分程式碼如下:

let redirectTo = '/insertForm?itemId=12345&isNewItem=yes'

...

endpoint: `/chkActiveProcess?redirectTo=${redirectTo}`

很簡單的字串相加,組合後會像這樣:

/chkActiveProcess?redirectTo=/insertForm?itemId=12345&isNewItem=yes

用上述的定義解釋這串網址實際執行後,參數部分會被如何解讀:

redirectTo -> /insertForm?itemId=12345
isNewItem -> yes

可以看到導向時想帶過去的參數少一個,被當成不相干的另一個參數了

要避免這種事情,需要使用網址傳遞資料時使用的編碼,代表用了這種編碼的部份都是資料,不會被誤判。
詳細可參考:https://zh.wikipedia.org/wiki/百分號編碼


以這次的例子,只要將「&」換成「%26」就行了,程式修正後如下

let redirectTo = '/insertForm?itemId=12345%26isNewItem=yes'

...

endpoint: `/chkActiveProcess?redirectTo=${redirectTo}`

不過%26這樣的東西,乍一看是認不出來的,打錯成%25搞不好也認不出來,這時就要善用工具了
各家語言都有網址編碼的函式可用,以javascript來說,可以這樣寫:

let redirectTo = '/insertForm?itemId=12345&isNewItem=yes'

...

endpoint: `/chkActiveProcess?redirectTo=${encodeURIComponent(redirectTo)}`

如此一來,不只是&,連同其他特殊符號如/、?、=都會被編碼(雖然這部分不編碼也不會出錯)。


這應該算是很基礎的常識,留個記錄希望以後不要再犯了。

CC BY-NC-ND 2.0