前言
本篇是介紹Alamofire 的基本使用闸衫,對(duì)于還不會(huì)引入Alamofire的小伙伴可以看《73-Swift之Pods(CocoaPods)的Alamofire的引入的詳細(xì)指導(dǎo)》勤揩。
Alamofire 是啥并级?
Alamofire是自2014年Swift 推出之后,AFNetworking的作者 [Mattt Thompson] 便提交了一個(gè)新的類似于AFNetworking 的網(wǎng)絡(luò)基礎(chǔ)框架肆氓,并且是專門使用最新的Swift 語(yǔ)言來(lái)編寫(xiě)的省店,其名為:Alamofire。
Alamofire 的優(yōu)點(diǎn)
- 鏈?zhǔn)降恼?qǐng)求/響應(yīng)方法(GET&POST等)
- URLEncoding / JSONEncoding / PropertyListEncoding 參數(shù)編碼
- 上傳類型支持:文件(File )智玻、數(shù)據(jù)(Data )、流(Stream)以及MultipartFormData
- 支持文件下載芙代,下載支持?jǐn)帱c(diǎn)續(xù)傳
- 支持使用NSURLCredential進(jìn)行身份驗(yàn)證
- HTTP響應(yīng)驗(yàn)證validate()
Alamofire 對(duì)請(qǐng)求結(jié)果的解析方法提供如下
response 以請(qǐng)求DefaultDataResponse的對(duì)象返回請(qǐng)求結(jié)果。
responseData 這是將請(qǐng)求的結(jié)果以二進(jìn)制流的形式解析盖彭。
responseJSON 這是將請(qǐng)求的結(jié)果以JSON的形式解析纹烹。
responseString 這是將請(qǐng)求的結(jié)果以字符串的形式解析。
responsePropertyList 這是將請(qǐng)求的結(jié)果以PLIST形式解析召边。
Alamofire 的GET請(qǐng)求方法和請(qǐng)求解析方法的介紹和使用
1铺呵、 無(wú)參數(shù)的Alamofire 的GET請(qǐng)求和解析方式的介紹
// MARK: Alamofire 的Get請(qǐng)求
func alamofireGet1() -> Void {
/**
該請(qǐng)求只有一個(gè)參數(shù) 'URLRequest',并返回請(qǐng)求對(duì)象(DataRequest)隧熙。我們可以處理請(qǐng)求對(duì)象(DataRequest)獲取我們需要的數(shù)據(jù)片挂。
*/
let dataRequest:DataRequest = Alamofire.request("http://www.reibang.com/u/23dd8d9701bf")
// 輸出請(qǐng)求返回的對(duì)象
print(dataRequest)
/**
輸出結(jié)果
GET http://www.reibang.com/u/23dd8d9701bf
*/
// 解析請(qǐng)求的對(duì)象
dataRequest.response { (DDResponse) in
// 獲取請(qǐng)求的狀態(tài)碼
let stateCode = DDResponse.response?.statusCode
print(stateCode!)
// 獲取請(qǐng)求的數(shù)據(jù)
print(DDResponse.data!)// 只輸出數(shù)據(jù)有多少字節(jié)數(shù)
// 將數(shù)據(jù)轉(zhuǎn)化為字符串
let dataStr = String.init(data: DDResponse.data!, encoding:String.Encoding.utf8)
print(dataStr!)
// TODO: 輸出請(qǐng)求對(duì)象
let requestSwf = DDResponse.request
print(requestSwf!)
/*通過(guò)請(qǐng)求對(duì)象,我們可以獲取請(qǐng)求的一系列信息*/
// 請(qǐng)求頭文件
print(requestSwf?.allHTTPHeaderFields as Any)
// 獲取請(qǐng)求的緩存規(guī)則
print(requestSwf?.cachePolicy as Any)
// 獲取請(qǐng)求體(body)
print(requestSwf?.httpBody as Any)
// 獲取請(qǐng)求的方法
print(requestSwf?.httpMethod as Any)
// TODO: 輸出請(qǐng)求響應(yīng)對(duì)象
let responseSwf = DDResponse.response
print(responseSwf!)
/**
輸出響應(yīng)對(duì)象:
<NSHTTPURLResponse: 0x608000221020> { URL: http://www.reibang.com/u/23dd8d9701bf } { status code: 200, headers {
"Cache-Control" = "max-age=0, private, must-revalidate";
Connection = "keep-alive";
"Content-Encoding" = gzip;
"Content-Type" = "text/html; charset=utf-8";
Date = "Sat, 30 Sep 2017 06:43:45 GMT";
Etag = "W/\"663fd325a56556576a8facd92d50bedd\"";
Server = Tengine;
"Set-Cookie" = "_maleskine_session=Y1JTZ2xhYnZ6b3dMZnZaZmVQeHZqVFN5L2QyWDJmaURtcVVBNXFGSXhRWlMvTUxzUWRhTkRFdy83NVAzbW0yNHhqQ05KNkN1WFJTTURTSkNYVnkzYmV6Wm96bmZyVU1kY0VQK3l6bENwN1JUVmdEaGtVY2NBUEdjbzBCZjAvdGVDTWRvRkhlZG16c2tjOGUzSnRvTVVBQWNNYUZyazhNRXlWellNeFFnNHFISTZMQ213bzFKNzV5OEdkYjF5VGRKbE9HdUJtWGpqV0VKU1RNcVJ3TktnMEFjclhFdFRtS3dKYngzek9pM2dWbGcyMmtQc0dLRU1RbDk2bUN2WW9jd3N3OWNMeFFqRkMrK08vYU5aWklEakxIanc2T1k3WjNsbFB1OVF4Rmd1VFZ0b1p2SFZnQ3l0WVVmZFM1KzZ4YmEzNTFhcjhVNHE5K0dacDlsM3RtMDBRPT0tLWxWaTQwNGpwVmZVaHdjNnc3Rk9teUE9PQ%3D%3D--a78f5fd47ad6bf048e57fd6701649281b26b2c63; path=/; HttpOnly";
"Transfer-Encoding" = Identity;
"X-Content-Type-Options" = nosniff;
"X-Frame-Options" = DENY;
"X-Request-Id" = "33b02181-e572-423c-ac45-a373e55edd6b";
"X-Runtime" = "0.078608";
"X-Via" = "1.1 wdx18:10 (Cdn Cache Server V2.0)";
"X-XSS-Protection" = "1; mode=block";
} }
*/
// TODO: 輸出請(qǐng)求的錯(cuò)誤信息
print(DDResponse.error as Any)
// TODO: 獲取請(qǐng)求/響應(yīng)統(tǒng)計(jì)信息的任務(wù)指標(biāo)贞盯。
print(DDResponse.metrics!)
}
// TODO: 以二進(jìn)制數(shù)據(jù)形式輸出請(qǐng)求結(jié)果(也可以說(shuō)解析請(qǐng)求結(jié)果)
dataRequest.responseData { (data) in
print(data)
/*輸出:SUCCESS: 24039 bytes */
}
//TODO: 以JSON形式的輸出請(qǐng)求數(shù)據(jù)(以JOSN形式解析結(jié)果)
dataRequest.responseJSON { (dataResponse) in
// 輸出一個(gè) 'DataResponse' 的對(duì)象
print(dataResponse)
// 通過(guò)‘DataResponse’ 我們可以獲取一些信息
// 1.請(qǐng)求的連接
print(dataResponse.request!)
// 2. 請(qǐng)求響應(yīng)的對(duì)象
print(dataResponse.response!)
// 3. 請(qǐng)求返回的數(shù)據(jù)
print(dataResponse.data!)
// 4. 服務(wù)器返回的結(jié)果
print(dataResponse.result)
// 5.完成請(qǐng)求需要的時(shí)間
print(dataResponse.timeline)
}
//TODO: 將返回?cái)?shù)據(jù)以字符串的形式解析
dataRequest.responseString { (dataResponse) in
// 輸出一個(gè) 'DataResponse' 的對(duì)象
print(dataResponse)
// 通過(guò)‘DataResponse’ 我們可以獲取一些信息
// 1.請(qǐng)求的連接
print(dataResponse.request!)
// 2. 請(qǐng)求響應(yīng)的對(duì)象
print(dataResponse.response!)
// 3. 請(qǐng)求返回的數(shù)據(jù)
print(dataResponse.data!)
// 4. 服務(wù)器返回的結(jié)果
print(dataResponse.result)
// 5.完成請(qǐng)求需要的時(shí)間
print(dataResponse.timeline)
}
//TODO: 將數(shù)據(jù)以PLIST文件形式輸出
dataRequest.responsePropertyList { (dataResponse) in
// 輸出一個(gè) 'DataResponse' 的對(duì)象
print(dataResponse)
// 通過(guò)‘DataResponse’ 我們可以獲取一些信息
// 1.請(qǐng)求的連接
print(dataResponse.request!)
// 2. 請(qǐng)求響應(yīng)的對(duì)象
print(dataResponse.response!)
// 3. 請(qǐng)求返回的數(shù)據(jù)
print(dataResponse.data!)
// 4. 服務(wù)器返回的結(jié)果
print(dataResponse.result)
// 5.完成請(qǐng)求需要的時(shí)間
print(dataResponse.timeline)
}
//TODO: 在線程中處理請(qǐng)求的數(shù)據(jù)
let dispathQu = DispatchQueue.main
dataRequest.response(queue: dispathQu) { (ddataResponse) in
// 返回一個(gè)‘DefaultDataResponse’ 對(duì)象
print(ddataResponse)
// 1音念、獲取請(qǐng)求體
print(ddataResponse.request!)
// 2、獲取請(qǐng)求響應(yīng)體
print(ddataResponse.response!)
// 3躏敢、獲取請(qǐng)求數(shù)據(jù)
print(ddataResponse.data!)
// 4闷愤、獲取請(qǐng)求的錯(cuò)誤信息
print(ddataResponse.error!)
}
// 請(qǐng)求的進(jìn)度
print(dataRequest.progress)
}
2、Alamofire的帶參數(shù)的GET請(qǐng)求
// TODO: Alamofire的GET請(qǐng)求帶參數(shù)
func alamofireGet2() -> Void {
let dataResponse = Alamofire.request("http://gc.ditu.aliyun.com/geocoding",parameters:["a":"北京"])
// 請(qǐng)求返回的結(jié)果
print(dataResponse)
// 對(duì)請(qǐng)求的結(jié)果處理
dataResponse.responseData { (dataRequ) in
if let data = dataRequ.data {
let strData = String.init(data: data, encoding: String.Encoding.utf8)
print(strData!)
/**
輸出的結(jié)果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
3件余、Alamofire的GET請(qǐng)求和返回?cái)?shù)據(jù)一起處理的寫(xiě)法
// TODO: Alamofire的GET請(qǐng)求和返回?cái)?shù)據(jù)一起處理的寫(xiě)法
func alamofireGet3() -> Void {
Alamofire.request("http://gc.ditu.aliyun.com/geocoding",parameters:["a":"北京"]).responseString { (dataResquest) in
if let data = dataResquest.data {
let strData = String.init(data: data, encoding: String.Encoding.utf8)
print(strData!)
/**
輸出的結(jié)果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
Alamofire 的POST請(qǐng)求
// MARK: Alamofire的POST請(qǐng)求
func alamofirePost() -> Void {
Alamofire.request("http://gc.ditu.aliyun.com/geocoding",method:.post ,parameters:["a":"北京"]).responseJSON { (dataRequest) in
if let data = dataRequest.data {
let strData = String.init(data: data, encoding: String.Encoding.utf8)
print(strData!)
/**
輸出的結(jié)果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
POST 和 GET 的友情快遞
對(duì)于POST 和 GET的區(qū)別是:GET產(chǎn)生一個(gè)TCP數(shù)據(jù)包讥脐;POST產(chǎn)生兩個(gè)TCP數(shù)據(jù)包遭居。對(duì)于GET方式的請(qǐng)求,瀏覽器會(huì)把http header和data一并發(fā)送出去旬渠,服務(wù)器響應(yīng)200(返回?cái)?shù)據(jù))俱萍; 而對(duì)于POST,瀏覽器先發(fā)送header告丢,服務(wù)器響應(yīng)100 continue枪蘑,瀏覽器再發(fā)送data,服務(wù)器響應(yīng)200 (返回?cái)?shù)據(jù))芋齿。
Alamofire 可以自定義請(qǐng)求
1腥寇、只定義請(qǐng)求方式的請(qǐng)求
// MARk:自定義請(qǐng)求
func customRequestMethod() -> Void {
// 創(chuàng)建請(qǐng)求體
let urlRequest = try! URLRequest.init(url: "http://www.reibang.com/u/23dd8d9701bf", method: .get)
Alamofire.request(urlRequest).responseString { (dataRequest) in
print(dataRequest.data!)
}
}
method 可選參數(shù)如下:
public enum HTTPMethod: String {
case options = "OPTIONS"
case get = "GET"
case head = "HEAD"
case post = "POST"
case put = "PUT"
case patch = "PATCH"
case delete = "DELETE"
case trace = "TRACE"
case connect = "CONNECT"
}
2、可是設(shè)置請(qǐng)求的緩存策略和請(qǐng)求超時(shí)的時(shí)間的請(qǐng)求
// MARK: 可是設(shè)置請(qǐng)求的緩存策略和請(qǐng)求超時(shí)的時(shí)間
func customRequestMethod1() -> Void {
// 創(chuàng)建請(qǐng)求體
let urlRequest = URLRequest.init(url: URL.init(string: "http://www.reibang.com/u/23dd8d9701bf")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30)
Alamofire.request(urlRequest).responseData { (dataQuest) in
print(dataQuest.data!)
}
}
@ cachePolicy 是請(qǐng)求緩存策略參數(shù)
@ timeoutInterval 是請(qǐng)求超時(shí)時(shí)間參數(shù)
3觅捆、可設(shè)置請(qǐng)求方式和請(qǐng)求頭的請(qǐng)求
// MARK: 可設(shè)置請(qǐng)求方式和請(qǐng)求頭的請(qǐng)求
func customRequestMethod2() -> Void {
// 創(chuàng)建請(qǐng)求體
let urlRequest = try! URLRequest.init(url: "http://www.reibang.com/u/23dd8d9701bf", method: .get, headers:["charset":"utf-8","Content-Type":"application/x-www-form-urlencoded","appKey":"NetWork小賤"])
Alamofire.request(urlRequest).responseData { (dataRequest) in
print(dataRequest.data!)
}
}
@ method 設(shè)置請(qǐng)求方式
@ headers 設(shè)置請(qǐng)求頭
Alamofire 的上傳參數(shù)編碼的請(qǐng)求
Alamofire 的請(qǐng)求參數(shù)編碼有以下幾種:
1赦役、 URLEncoding 是 “URL” 網(wǎng)址編碼規(guī)則
2、 JSONEncoding 是 “JSON” 格式編碼規(guī)則
3栅炒、 PropertyListEncoding 是 “PLIST” 文件編碼規(guī)則
使用舉例如下:
//MARK: 上傳參數(shù)使用指定的編碼格式上傳的請(qǐng)求
func parameterCodingRequest() -> Void {
// 請(qǐng)求的參數(shù)
let parameter = ["type":"hot","offset":"0","limit":"10"]
/**
參數(shù)的所有編碼形式如下,即 “ParameterEncoding” 的擴(kuò)展對(duì)象:
1掂摔、 URLEncoding 是 “URL” 網(wǎng)址編碼規(guī)則
2、 JSONEncoding 是 “JSON” 格式編碼規(guī)則
3赢赊、 PropertyListEncoding 是 “PLIST” 文件編碼規(guī)則
*/
Alamofire.request("http://m.maoyan.com/movie/list.json", method: .get, parameters: parameter,
encoding: URLEncoding.default).responseJSON { (dataRequest) in
if let data = dataRequest.data {
print(String.init(data: data, encoding: String.Encoding.utf8)!)
}
}
}
Alamofire 的 validate() 函數(shù)的介紹
1乙漓、 validate() 函數(shù)是啥?
確認(rèn)響應(yīng)有默認(rèn)可接受的200~299范圍內(nèi)的狀態(tài)碼释移,還有內(nèi)容類型匹配在Accept HTTP頭字段中指定的任何值叭披。如果驗(yàn)證失敗,隨后對(duì)響應(yīng)處理程序的調(diào)用將會(huì)有一個(gè)相關(guān)的錯(cuò)誤玩讳。
2涩蜘、請(qǐng)求信息的驗(yàn)證之 “validate”
// MARK: 請(qǐng)求信息的驗(yàn)證之 “validate”
func verifyInformationRequest() -> Void {
Alamofire.request("http://m.maoyan.com/cinemas.json").validate().responseJSON { (dataRequest) in
switch dataRequest.result.isSuccess {
case true:
let data = dataRequest.data
let dict = try! JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
print(dict)
case false:
print("獲取信息失敗Q俊同诫!")
}
}
}
3、驗(yàn)證請(qǐng)求狀態(tài)碼在 “200~299” 之間的請(qǐng)求樟澜,否則误窖,不驗(yàn)證。
// MARK: 驗(yàn)證請(qǐng)求狀態(tài)碼在 “200~299” 之間的請(qǐng)求秩贰,否則霹俺,不驗(yàn)證。
func requestStateCodeVerification() -> Void {
Alamofire.request("http://m.maoyan.com/cinemas.json").validate(statusCode: [200,299]).responseJSON { (dataRequest) in
switch dataRequest.result.isSuccess {
case true:
if let data = dataRequest.data {
let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
print(dict)
}
case false:
print("獲取信息失敹痉选?苑!蝗罗!")
}
}
}
4艇棕、驗(yàn)證指定請(qǐng)求媒體信息格式的請(qǐng)求
// MARK: 驗(yàn)證指定請(qǐng)求媒體信息格式的請(qǐng)求
func verifyRequestMediaFormatRequest() -> Void {
/**
友情大爆炸:
1蝌戒、contentType : 即是 “Internet Media Type” 稱之為 互聯(lián)網(wǎng)媒體類型,也叫 “MIME”沼琉。作用是在 "HTTP" 請(qǐng)求頭中使用“contentType”來(lái)指定不同格式的請(qǐng)求信息北苟。
2、contentType 常見(jiàn)的媒體格式類型如下:
text/html :HTML格式
text/plain :純文本格式
text/xml :XML格式
image/gif :gif圖片格式
image/jpeg :jpg圖片格式
image/png :png圖片格式
以application開(kāi)頭的媒體格式類型:
application/xhtml+xml :XHTML格式
application/xml :XML數(shù)據(jù)格式
application/atom+xml :Atom XML聚合格式
application/json :JSON數(shù)據(jù)格式
application/pdf :pdf格式
application/msword :Word文檔格式
application/octet-stream :二進(jìn)制流數(shù)據(jù)(如常見(jiàn)的文件下載)
application/x-www-form-urlencoded :<form encType=””>中默認(rèn)的encType打瘪,form表單數(shù)據(jù)被編碼為key/value格式發(fā)送到服務(wù)器(表單默認(rèn)的提交數(shù)據(jù)的格式)
*/
Alamofire.request("http://m.maoyan.com/cinemas.json").validate(contentType: ["text/html","text/plain","application/json"]).responseJSON { (dataRequest) in
switch dataRequest.result.isSuccess {
case true:
if let data = dataRequest.data {
let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
print(dict)
}
case false:
print("獲取信息失斢驯恰!9肷А彩扔!")
}
}
}
5、我們可以根據(jù)某個(gè)條件僻爽,來(lái)設(shè)定返回的驗(yàn)證結(jié)果 “ValidationResult”
// MARK: 我們可以根據(jù)某個(gè)條件虫碉,來(lái)設(shè)定返回的驗(yàn)證結(jié)果 “ValidationResult”
func customizationValidationResult() -> Void {
Alamofire.request("http://m.maoyan.com/cinemas.json").validate { (urlRequest, httpUrlResponse, data) -> Request.ValidationResult in
// 在這里我們可以提前檢驗(yàn) 請(qǐng)求的 “URLRequest”、“HTTPURLResponse” 和 返回的數(shù)據(jù) “Data” 等來(lái)設(shè)置請(qǐng)求返回的 “ValidationResult”
if !(urlRequest?.url?.absoluteString.contains("NetWork"))! {
let error = NSError.init(domain: "m.maoyan.com", code: 320, userInfo: ["msg":"請(qǐng)求不包含指定的參數(shù)"]) as Error
return Request.ValidationResult.failure(error)
}
return Request.ValidationResult.success
}.responseJSON { (dataRequest) in
switch dataRequest.result.isSuccess {
case true:
if let data = dataRequest.data {
let dict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)
print(dict)
}
case false:
let errorInfo = dataRequest.result.error! as NSError
print(errorInfo.userInfo)
/**
輸出信息:["msg": "請(qǐng)求不包含指定的參數(shù)"]
*/
}
}
}