理解HTTP之Content-Type


0x01.About

查看 Restful API 報頭插件:Chrome插件REST Console,以及發(fā)送 Restful API 工具:Chrome插件POST Man

HTTP 1.1 規(guī)范中竞穷,HTTP 請求方式有 OPTIONS胚宦、GET杯缺、HEAD掏愁、POST、PUT毫炉、DELETE瓮栗、TRACE、CONNECT瞄勾。通常我們用的只有 GET费奸、POST,然而對于 Restful API 規(guī)范來說进陡,請求資源要用 PUT 方法愿阐,刪除資源要用 DELETE 方法。

例如發(fā)送個 DELETE 包:

http://example.com/my/resource?id=12345

那么通過 id 就能獲取到信息四濒,這個包只有 header换况,并不存在 body职辨,下面討論幾個包含body 的發(fā)包的 body 傳輸格式。

0x02.Content-Type

Content-Type 用于指定內(nèi)容類型戈二,一般是指網(wǎng)頁中存在的 Content-Type舒裤,Content-Type
屬性指定請求和響應(yīng)的 HTTP 內(nèi)容類型。如果未指定 ContentType觉吭,默認為 text/html腾供。

nginx 中有個配置文件 mime.types,主要是標示 Content-Type 的文件格式鲜滩。

下面是幾個常見的 Content-Type

  • text/html
  • text/plain
  • text/css
  • text/javascript
  • application/x-www-form-urlencoded
  • multipart/form-data
  • application/json
  • application/xml
  • ......

前面幾個都很好理解伴鳖,都是 htmlcss徙硅、javascript 的文件類型榜聂,后面四個是 POST 的發(fā)包方式。

0x03.application/x-www-form-urlencoded

application/x-www-form-urlencoded 是常用的表單發(fā)包方式嗓蘑,普通的表單提交须肆,或者 js 發(fā)包,默認都是通過這種方式桩皿。

比如一個簡單地表單:

<form enctype="application/x-www-form-urlencoded" action="http://homeway.me/post.php" method="POST">
    <input type="text" name="name" value="homeway">
    <input type="text" name="key" value="nokey">
    <input type="submit" value="submit">
</form>

那么服務(wù)器收到的 raw header 會類似:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,gl;q=0.2,de;q=0.2
Cache-Control:no-cache
Connection:keep-alive
Content-Length:17
Content-Type:application/x-www-form-urlencoded

那么服務(wù)器收到的 raw body 會是:name=homeway&key=nokey豌汇,在 php 中,通過$_POST 就可以獲得數(shù)組形式的數(shù)據(jù)泄隔。

0x04.multipart/form-data

multipart/form-data 用在發(fā)送文件的POST包拒贱。

這里假設(shè)我用 pythonrequest 發(fā)送一個文件給服務(wù)器:

data = {
    "key1": "123",
    "key2": "456",
}
files = {'file': open('index.py', 'rb')}
res = requests.post(url="http://localhost/upload", method="POST", data=data, files=files)
print res

通過工具,可以看到我發(fā)送的數(shù)據(jù)內(nèi)容如下:

POST http://www.homeway.me HTTP/1.1
Content-Type:multipart/form-data; boundary=------WebKitFormBoundaryOGkWPJsSaJCPWjZP

------WebKitFormBoundaryOGkWPJsSaJCPWjZP
Content-Disposition: form-data; name="key2"
456
------WebKitFormBoundaryOGkWPJsSaJCPWjZP
Content-Disposition: form-data; name="key1"
123
------WebKitFormBoundaryOGkWPJsSaJCPWjZP
Content-Disposition: form-data; name="file"; filename="index.py"

這里 Content-Type 告訴我們佛嬉,發(fā)包是以 multipart/form-data 格式來傳輸逻澳,另外,還有 boundary 用于分割數(shù)據(jù)暖呕。

當文件太長赡盘,HTTP 無法在一個包之內(nèi)發(fā)送完畢,就需要分割數(shù)據(jù)缰揪,分割成一個一個 chunk 發(fā)送給服務(wù)端陨享,
那么 -- 用于區(qū)分數(shù)據(jù)快,而后面的數(shù)據(jù) ------WebKitFormBoundaryOGkWPJsSaJCPWjZP
就是標示區(qū)分包作用钝腺。

0x05.text/xml

微信用的是這種數(shù)據(jù)格式發(fā)送請求的抛姑。

POST http://www.homeway.me HTTP/1.1 
Content-Type: text/xml

<?xml version="1.0"?>
<resource>
    <id>123</id>
    <params>
        <name>
            <value>homeway</value>
        </name>
        <age>
            <value>22</value>
        </age>
    </params>
</resource>

php$_POST 只能讀取 application/x-www-form-urlencoded 數(shù)據(jù),$_FILES 只能讀取 multipart/form-data 類型數(shù)據(jù)艳狐,那么定硝,要讀取 text/xml 格式的數(shù)據(jù),可以用:

file=fopen(‘php://input′,‘rb′);
data = fread(file,length);
fclose(file);

或者

$data = file_get_contents(‘php://input’);

0x06.application/json

通過 json 形式將數(shù)據(jù)發(fā)送給服務(wù)器毫目,一開始蔬啡,我嘗試通過 curl诲侮,給服務(wù)器發(fā)送application/json 格式包,然而我收到的數(shù)據(jù)如下:

————————–e1e1406176ee348a 
Content-Disposition: form-data; name=”nid” 2 ————————–e1e1406176ee348a 
Content-Disposition: form-data; name=”uuid” cf9dc994-a4e7-3ad6-bc54-41965b2a0dd7 ————————–e1e1406176ee348a 
Content-Disposition: form-data; name=”access_token” 956731586df41229dbfec08dd5d54eedb98d73d2 ————————–e1e1406176ee348a–

后來想想明白了箱蟆,HTTP 通信中并不存在所謂的 json沟绪,而是將 string 轉(zhuǎn)成 json 罷了,也就是空猜,application/json 可以將它理解為 text/plain绽慈,普通字符串。

之所以出現(xiàn)那么多亂七八糟的 ------- 應(yīng)該是 php 數(shù)組傳輸進去辈毯,存在的轉(zhuǎn)換問題吧(我目前能想到的原因)坝疼。

本文出自 夏日小草,轉(zhuǎn)載請注明出處:http://homeway.me/2015/07/19/understand-http-about-content-type/

iOS 通過 POST 上傳圖片

iOS 上傳圖片以 multipart/form-data 進行上傳。

  1. 使用 URLRequest
func uploadAvatar() {
    var request  = URLRequest(url: URL(string: "https://xxxxx")!)
    request.httpMethod = "POST"
    let boundary = "Boundary-\(UUID().uuidString)"
    let params = ["userId": "123", "token": "xxxxxxx"]
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
    request.httpBody = createBody(parameters: params,
                            boundary: boundary,
                            data: UIImageJPEGRepresentation(chosenImage, 1.0)!,
                            mimeType: "image/jpg",
                            filename: "avatar.jpg")
}
func createBody(parameters: [String: String],
                boundary: String,
                data: Data,
                mimeType: String,
                filename: String) -> Data {
    let body = NSMutableData()
    
    let boundaryPrefix = "--\(boundary)\r\n"
    
    for (key, value) in parameters {
        body.appendString(boundaryPrefix)
        body.appendString("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n")
        body.appendString("\(value)\r\n")
    }
    
    body.appendString(boundaryPrefix)
    body.appendString("Content-Disposition: form-data; name=\"file\"; filename=\"\(filename)\"\r\n")
    body.appendString("Content-Type: \(mimeType)\r\n\r\n")
    body.append(data)
    body.appendString("\r\n")
    body.appendString("--".appending(boundary.appending("--")))
    
    return body as Data
}
extension NSMutableData {
    func appendString(_ string: String) {
        let data = string.data(using: String.Encoding.utf8, allowLossyConversion: false)
        append(data!)
    }
}
  1. 使用 Moya
/// 實際網(wǎng)絡(luò)請求對象
var task: Task {
    switch self {
    case .uploadAvatar(let model):
        guard let data = model.data else { return .request }
        let token = "xxxxxx".data(using: String.Encoding.utf8, allowLossyConversion: false)
        let userId = "123".data(using: String.Encoding.utf8, allowLossyConversion: false)
        let tokenData = MultipartFormData(provider: .data(token!), name: "token")
        let userIdData = MultipartFormData(provider: .data(userId!), name: "userId")
        let imgData = MultipartFormData(provider: .data(data), name: "file", fileName: "avatar.jpg", mimeType: "image/jpg")
        return .upload(.multipart([userIdData, tokenData, imgData]))
    default:
        return .request
    }
}

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谆沃,一起剝皮案震驚了整個濱河市钝凶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唁影,老刑警劉巖腿椎,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夭咬,居然都是意外死亡,警方通過查閱死者的電腦和手機铆隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門卓舵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人膀钠,你說我怎么就攤上這事掏湾。” “怎么了肿嘲?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵融击,是天一觀的道長。 經(jīng)常有香客問我雳窟,道長尊浪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任封救,我火速辦了婚禮拇涤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘誉结。我一直安慰自己鹅士,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布惩坑。 她就那樣靜靜地躺著掉盅,像睡著了一般也拜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上趾痘,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天慢哈,我揣著相機與錄音,去河邊找鬼扼脐。 笑死岸军,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的瓦侮。 我是一名探鬼主播艰赞,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肚吏!你這毒婦竟也來了方妖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤罚攀,失蹤者是張志新(化名)和其女友劉穎党觅,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斋泄,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡杯瞻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了炫掐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魁莉。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖募胃,靈堂內(nèi)的尸體忽然破棺而出旗唁,到底是詐尸還是另有隱情,我是刑警寧澤痹束,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布检疫,位于F島的核電站,受9級特大地震影響祷嘶,放射性物質(zhì)發(fā)生泄漏屎媳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一论巍、第九天 我趴在偏房一處隱蔽的房頂上張望剿牺。 院中可真熱鬧,春花似錦环壤、人聲如沸晒来。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湃崩。三九已至荧降,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攒读,已是汗流浹背朵诫。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留薄扁,地道東北人剪返。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像邓梅,于是被迫代替她去往敵國和親脱盲。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理日缨,服務(wù)發(fā)現(xiàn)钱反,斷路器,智...
    卡卡羅2017閱讀 134,601評論 18 139
  • 整體Retrofit內(nèi)容如下: 1匣距、Retrofit解析1之前哨站——理解RESTful2面哥、Retrofit解析2...
    隔壁老李頭閱讀 15,037評論 4 39
  • # 一度蜜v3.0協(xié)議 --- # 交互協(xié)議 [TOC] ## 協(xié)議說明 ### 請求參數(shù) 下表列出了v3.0版協(xié)...
    c5e350bc5b40閱讀 640評論 0 0
  • HTTP全稱為HyperText Transfer Protocol,從名字不難看出這是一種基于文本的網(wǎng)絡(luò)協(xié)議毅待,對...
    MrPeak閱讀 1,449評論 3 21
  • 取前3個字符 取后3個字符 遍歷字符串 插入字符串 替換字符串 字符串切片,獲取interesting 字符串切片...
    Roct閱讀 1,293評論 0 2