http報(bào)文格式
借用網(wǎng)上一個(gè)圖
總結(jié)起來就是url(請(qǐng)求行)— header(請(qǐng)求頭部)— body(請(qǐng)求數(shù)據(jù))
完整的http網(wǎng)絡(luò)請(qǐng)求有兩個(gè)報(bào)文庶近,一個(gè)是請(qǐng)求報(bào)文,一個(gè)是響應(yīng)報(bào)文训挡。這里只關(guān)注請(qǐng)求報(bào)文澳骤。
header里有很多字段歧强,比較常用的就是content-type字段,這個(gè)字段決定了body的編碼格式为肮。
Content-Type常見的幾種格式
-
application/x-www-form-urlencoded url編碼
說明body中的東西看起來是這樣的
id=1234&name=%E5%86%85%E5%AD%98%E4%BB%8B%E7%BB%8D/
這種有百分號(hào)的編碼叫URLEncoding摊册,又叫百分號(hào)編碼
-
application/json
這種編碼是現(xiàn)在接口請(qǐng)求中最常用的格式,表示body里的內(nèi)容是json字符格式
{
? "name": xxxx,
? "id": 1234
}
-
multipart/form-data
這個(gè)格式的body由0到多個(gè)item組成颊艳,item之間有分界線茅特。item內(nèi)部也有head和body,item的head由content-disposition和content-type組成棋枕。借用這篇文章的例子說明一下格式
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data; name="city" Santa colo --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="desc" Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC Content-Disposition: form-data;name="pic"; filename="photo.jpg" Content-Type: application/octet-stream Content-Transfer-Encoding: binary ... binary data of the jpg ... --ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--
URLSession中組織http請(qǐng)求報(bào)文
下面是一個(gè)使用URLSession實(shí)現(xiàn)的沒有參數(shù)的網(wǎng)絡(luò)請(qǐng)求
let request = URLRequest(url: URL(string: "https://www.baidu.com")!)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
}
task.resume()
系統(tǒng)提供的URLSession網(wǎng)絡(luò)庫不會(huì)幫我們組織http報(bào)文白修。如果我們想帶上參數(shù),就得自己組織http報(bào)文重斑。如果想像get的方式增加參數(shù)熬荆,就得手動(dòng)修改url進(jìn)行參數(shù)拼接。如果想把數(shù)據(jù)放在body里绸狐,得把自己要傳輸?shù)臄?shù)據(jù)組織成urlencode或json或其他想要格式的數(shù)據(jù)卤恳,然后把數(shù)據(jù)用utf8編碼變成二進(jìn)制,放到request的httpBody屬性上寒矿,再設(shè)置一下header的content-type成對(duì)應(yīng)類型突琳。如果是urlencode,就這樣設(shè)置
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
或者這樣
request.setValue("application/x-www-form-urlencoded; charset=UTF-8", forHTTPHeaderField: "Content-Type")
var urlString = "https://www.baidu.com"
urlString.append("?name=xxx&id=1234") //GET,把參數(shù)拼接到url后面符相。這里省略了urlencode編碼拆融。
var request = URLRequest(url: URL(string: urlString)!)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
}
task.resume()
var urlString = "https://www.baidu.com"
var request = URLRequest(url: URL(string: urlString)!)
// POST,把json格式的參數(shù)放到body里
do {
let bodyJsonData = try JSONSerialization.data(withJSONObject: ["name": "xxxx", "id": 12133], options: JSONSerialization.WritingOptions.prettyPrinted)
request.httpBody = bodyJsonData
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
} catch {
}
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
}
task.resume()
Alamofire組織http報(bào)文
使用Alamofire組織一個(gè)參數(shù)拼接到url上的請(qǐng)求:
let urlString = "https://www.baidu.com"
let param = ["name": "xxxx", "id": 12133] as [String : Any]
request(URL(string: urlString)!, method: .get, parameters: param, encoding: URLEncoding.queryString, headers: nil).response { (response) in
}
可以看到我們直接傳了一個(gè)參數(shù)字典給Alamofire,所以是Alamofire幫我們把傳進(jìn)去的param進(jìn)行url編碼啊终,然后拼到url后面镜豹。如果request方法到ecoding參數(shù)給URLEncoding.httpBody,Alamofire是會(huì)把參數(shù)進(jìn)行url編碼蓝牲,然后進(jìn)行utf8編碼轉(zhuǎn)變成二進(jìn)制數(shù)據(jù)放到request的httpbody上
Alamofire中負(fù)責(zé)組織數(shù)據(jù)的是遵循ParameterEncoding協(xié)議的類趟脂,Alamofire中遵循這個(gè)協(xié)議的有三個(gè)類 URLEncoding、JSONEncoding例衍、PropertyListEncoding昔期,我們也可以根據(jù)需要自定義。顧名思義佛玄,這幾個(gè)類分別負(fù)責(zé)url編碼硼一、json格式數(shù)據(jù)組織、plist文件格式數(shù)組組織梦抢。Alamofire按照request方法中的encoding參數(shù)對(duì)數(shù)據(jù)進(jìn)行組織般贼。JSONEncoding和PropertyListEncoding組織的數(shù)據(jù)只能放在httpbody中,而URLEncoding組織的數(shù)據(jù)可以拼接在url后面。
Moya的方式
下面是一個(gè)把參數(shù)用URLEncoding編碼方式放到httpbody中的網(wǎng)絡(luò)請(qǐng)求
//首先把request里需要的數(shù)據(jù)定義出來
enum BaiduAPI {
case home
}
extension BaiduAPI: TargetType {
var baseURL: URL {
return URL(string: "https://www.baidu.com")!
}
var path: String {
return ""
}
var method: Moya.Method {
return .post
}
var sampleData: Data {
return Data()
}
var task: Task {
return .requestParameters(parameters: ["name": "xxxx", "id": 12133], encoding: URLEncoding.httpBody)
}
var headers: [String : String]? {
return nil
}
}
func moyaQuest() {
let moya = MoyaProvider<BaiduAPI>()
moya.request(BaiduAPI.home) { (result) in
}
}
可以看到moya把http請(qǐng)求報(bào)文需要的信息都模版化了哼蛆。其中task屬性是數(shù)據(jù)承載體蕊梧,也是承載著數(shù)據(jù)組織形式。Task是個(gè)枚舉人芽,它給開發(fā)者提供了幾種數(shù)據(jù)的組合方式,比如同時(shí)需要把參數(shù)拼接在url上和放到body里的場(chǎng)景绩脆,可以用requestCompositeData萤厅,requestCompositeParameters,uploadCompositeMultipart靴迫。Moya會(huì)把TargetType轉(zhuǎn)成EndPoint惕味,再把EndPoint轉(zhuǎn)成URLRequest。