在處理slack app 收到的slack request/response message時,出現了一個很頭痛的問題,那就是slack 會自動在message中幫我把原始訊息裡的空白(space) 變成 + 號,這樣做法的困擾就是很難百分百還原訊息內容。
而原本同事的做法是索性就把+號用string.replace方法用space取代回來,但這樣也會把原訊息中的加號變成空白,最直接的衝擊就是我們的wiki url難免會有一些+號,一旦用空白取代掉,url就點不開了。
後來仔細想想為何slack堅持自動把收到的原始訊息中的空白變加號,這直覺一定是http encode編碼方法攪的鬼,slack應該是收到訊息時就已經空白變加號了,只是沒細想一般人應該很容易會把slack變替死鬼。
再進去看看我們是怎麼透過slack 介面post我們的資料的,發現我們是用Content Type 為 application/x-www-form-urlencoded 的方式向slack送出我們的資料,而問題正是出在這個神奇的 application/x-www-form-urlencoded content type。
其實 application/x-www-form-urlencoded 是一種url編碼標準,它有一個比較特別的功用是當使用者用post方法傳遞request body時,可以變成以query string的方式把request body附在url後面傳遞出去,看起來就像是傳統get 使用query string來傳遞參數。
先看看網路怎麼說明POST與GET的不同:"使用http上传数据可以用GET或POST,使用GET的话,只能通过uri的queryString形式,这会遇到长度的问题,各个浏览器或server可能对长度支持的不同,所以到要提交的数据如果太长并不适合使用GET提交。"[1] 一般get傳遞會有長度限制,而post傳遞參數比較沒有這個問題。
但是POST也可以透過編碼的方式將body以query string附帶在url後面傳遞出去:"采用POST的话,既可以在uri中带有queryString也可以将数据放在body中。body内容可以有多种编码形式,其中application/x-www-form-urlencoded
编码其实是基于uri的percent-encoding
编码的,所以采用application/x-www-form-urlencoded
的POST数据和queryString只是形式不同,本质都是传递参数。"[1]
所以application/x-www-form-urlencoded主要是用來幫POST以query string方式把request body附加在URL後面來傳遞。
其實application/x-www-form-urlencoded url編碼方式是早期HTML 4的表單傳遞標準方法,只是因為早期的表單資料相對單純,因此即使是用post method也會以這種編碼方式把表單參數以query string送出。
但是x-www-form-urlencoded url編碼有一個副作用就是會把原始訊息中的空白符號轉成加號,這是因為x-www-form-urlencoded並非標準的url 編碼,它的做法並不是把url的空白符號編成”%20”,反而是編成”+”號[2],也正因為如此,所以當request body變成url 的query string 參數時就自動被加號給取代空白了。
所以解法就出現了,那就是把x-www-form-urlencoded編碼過的query string再解碼(decode)回來,也就是把加號還原成空白,在python 3是使用
import urllib.parse
raw_json = urllib.parse.parse_qs(“被x-www-form-urlencoded編碼過的query string”)
來完成。要特別一提的是,這個 urllib.parse.parse_qs method 不僅會把加號還原成空白,還會把query string變成json 物件。[3]
所以結論就是單靠一句 urllib.parse.parse_qs(“被x-www-form-urlencoded編碼過的query string”) 便解決slack總是把原始訊息的空白變加號這個問題,但是一切得知道原因是出在 這個傳統url 編碼方式身上,而現代的url編碼方式則會把任何特殊url字元轉成”%”開頭的字元編號。
[Reference]
- 关于application/x-www-form-urlencoded编码, https://blog.csdn.net/shmily_lsl/article/details/79940366
- [故障引起的故事]URL中带加号的处理, https://agapple.iteye.com/blog/773061
- python: how to convert a query string to json string?, https://stackoverflow.com/questions/11912843/python-how-to-convert-a-query-string-to-json-string
2019年2月6日星期三
留言列表