HTTP的GET請求能傳圖片嗎?
阿新 • • 發佈:2022-04-04
從一道面試題說起:GET 請求能傳圖片嗎?
# 前 言
曾經遇到的面試題,覺得挺有意思,來說下我的答案及思考過程。
首先,我們要知道的是,圖片一般有兩種傳輸方式:base64 和 file物件。
# base64 圖片
圖片的base64編碼想必大家都見過。
base64 的本質是字串,而 GET 請求的引數在 url 裡面,所以直接把圖的 base64 資料放到 url 裡面,就可以實現 GET 請求傳圖片。
input 輸入框拿到的圖是 file 物件,圖片 file 物件轉 base64 :
// img引數:file檔案或者blob
const getBase64 = img => {
return new Promise((resolve,reject) => {
const reader = new FileReader();
reader.onload = e => {
resolve(e.target.result);
};
reader.onerror = e => reject(e);
reader.readAsDataURL(img);
})
}
問題來了,GET 請求的 url 長度是有限制的,不同的瀏覽器長度限制不一樣,最長的大概是 10k 左右,根據 base64 的編碼原理,base64圖片大小比原檔案大小大 1/3,所以說 base64 只能傳一些非常小的小圖,大圖的 base64 太長會被截斷。但其實這個長度限制是瀏覽器給的,而不是 GET 請求本身,也就說,在服務端,GET 請求長度理論上無限長,也就是可以傳任意大小的圖片。
# file 物件
我們來看看這個場景:
<form action="http://localhost:8080/" method="get">
<input type="file" name="logo">
<input type="submit">
</form>
選擇圖片,然後提交表單,能提交成功,但是介面收不到檔案。請求的 url 會變成 http://localhost:8080/?logo=xxx.png,但是不會攜帶圖片資料。
正常情況,file 物件資料是放在POST請求的 body 裡面,並且是 form-data 編碼。那麼 GET 請求能否有 body 體呢?
答案是可以有。
GET 和 POST 並沒有本質上的區別,他們只是 HTTP 協議中兩種請求方式,僅僅是報文格式不同(或者說規範不同)。
舉個栗子, 一個普通的 GET 請求,他們收到是這樣的:
GET /test/?sex=man&name=zhangsan HTTP/1.1
Host: http://localhost:8080
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: Keep-Alive
POST 請求長這樣:
POST /add HTTP/1.1
Host: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive
sex=man&name=Professional
GET 請求能不能帶 body 這個事是由 HTTP 協議來定義的。
所謂協議就是大家共同遵守的一套規則,你不遵守某一規則有時候確實不會有大問題,但是其行為表現是什麼就不得而知了。協議帶來規範化,規範化帶來高效。事實是 HTTP 1.1 的 RFC 文件裡沒有禁止 GET 請求帶 body ,但是也沒有定義 GET 請求 body 的語義。
參見: tools.ietf.org。
A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
# 總 結
作為面試題的話,本題大概有兩個考點:
1、二進位制圖片序列化 base64;
2、特定場景的 url 長度限制。
3、部分 http 協議知識。
或者說,真要 get 傳圖片作為方案的話,需要打通上面兩個關鍵技術問題。面試現場也可以再加一些Blob、TypedArray、圖片壓縮方案之類的。