本文的目的是單純的翻譯一下Alamofire的基本用法的文檔券犁,原文是在github上:https://github.com/Alamofire/Alamofire/blob/master/Documentation/Usage.md 你看到這篇文章的時候芋类,可能官方文檔會有更新(本文5.1.0版本)虑乖。個人也是按照自己的理解進行翻譯粤剧,能力有限贿讹,翻譯的不好的地方苛聘,希望看到的朋友們給我指正出來养篓,感激不盡~
使用 Alamofire
介紹
Alamofire 提供了一個優(yōu)雅的和可組合的接口去進行 HTTP 網(wǎng)絡請求秃流。它是在 Apple 官方的 Foundation 框架所提供的 URL Loading System 之上建立起來的,并不是自己去實現(xiàn)了這些HTTP的請求相關的功能柳弄。 URL Loading System 的核心是 URLSession 和 URLSessionTask 的子類們舶胀。Alamofire 把包括他們在內(nèi)的許多 API 封裝成了更加易于使用的API(interface)并且提供了開發(fā) App(需要使用 HTTP 網(wǎng)絡請求的) 所需要的各種網(wǎng)絡方面的功能。但是碧注,很重要的一點是你要知道 Alamofire 的核心功能是來自哪里的(URL Loading System )嚣伐,因此,熟悉 Apple 的 URL Loading System是很重要的萍丐。歸根結底轩端,Alamofire 的網(wǎng)絡功能是受限制于 URL Loading System 的能力的,因此遵守 URL Loading System 的行為和準則是必須的逝变。
另外基茵,在 Alamofire (和 URL Loading System 的一般情況)下的網(wǎng)絡請求都是異步的奋构。異步編程可能使不熟悉這個概念的程序員感到沮喪,但是異步編程的 好處 是非常多的拱层。
旁注:AF命名空間和參考
以前版本的 Alamofire 的文檔都使用了 Alamofire.request()
這樣的示例來進行網(wǎng)絡請求弥臼。這個 API 使用了Alamofire 的前綴,但是事實上沒有這個前綴根灯,也是可以的径缅。在任何文件中 import Alamofire
都可以在文件中全局的使用 request
以及其他的方法(functions)。從 Alamofire 5 版本開始烙肺,這種使用方法被移除了纳猪,取而代之的是 AF
這個全局的對 Session.default
的引用(AF = Session.default)。這樣做的好處是使得在每次使用 Alamofire 提供的便捷的功能的時候不會去污染 Alamofire
的全局命名空間茬高,也不用每次使用 Alamofire 的時候都寫一遍全局的 Session
API兆旬。同樣的原因,Alamofire 拓展出來的類型們會使用 af
這種拓展名來把 Alamofire 提供的功能和其他拓展所提供的功能進行區(qū)分怎栽。
發(fā)一個網(wǎng)絡請求(Making Requests)
Alamofire 提供了多個便捷的方法去發(fā)送網(wǎng)絡請求丽猬。最簡單的例子,只需要提供一個可以轉(zhuǎn)換成(converted into)URL
的 String
就可以了 (第一個版本):
AF.request("https://httpbin.org/get").response { response in
debugPrint(response)
}
注:所有的例子都需要在文件中
import Alamofire
這個方法實際上是 Alamofire 的 Session
發(fā)送網(wǎng)絡請求的兩個頂層(top-level) API 中的一個熏瞄,他的完整定義是這樣的:
open func request<Parameters: Encodable>(_ convertible: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoder: ParameterEncoder = URLEncodedFormParameterEncoder.default,
headers: HTTPHeaders? = nil,
interceptor: RequestInterceptor? = nil) -> DataRequest
這個方法創(chuàng)建了一個 DataRequest
脚祟。在創(chuàng)建每個請求(request)的時候允許他們有自己不同的組成元素(components),他們可以有不同的 method
或者 headers
强饮。 還允許每個請求都可以有自己的攔截器(RequestInterceptor
)和 參數(shù)編碼(Encodable)由桌。
除上面之外還有一些額外的方法可以讓你使用
Parameters
類型的字典做為參數(shù)ParameterEncoding
作為參數(shù)類型進行網(wǎng)絡請求。不建議再這些 API 了邮丰,它們會在將來被 Alamofire 移除掉行您。
這個 API 的 第二個版本 要簡單的多:
open func request(_ urlRequest: URLRequestConvertible,
interceptor: RequestInterceptor? = nil) -> DataRequest
這個方法可以為任何一個符合 Alamofire 的 URLRequestConvertible
協(xié)議的類型創(chuàng)建一個 DataRequest
。所有之前版本的參數(shù)(對比上一個完整的函數(shù)中的參數(shù))都被封裝進了這個 URLRequestConvertible
的參數(shù)里面剪廉,這樣就產(chǎn)生了一個非常強大的抽象娃循。這一點我們在 高級用法 的文檔中進行了討論。
HTTP 請求方式 (HTTP Methods)
HTTPMethod
這個類型列舉出了 RFC 7231 §4.3 中定義的 HTTP 請求方式們(HTTP Methods):
public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
public static let connect = HTTPMethod(rawValue: "CONNECT")
public static let delete = HTTPMethod(rawValue: "DELETE")
public static let get = HTTPMethod(rawValue: "GET")
public static let head = HTTPMethod(rawValue: "HEAD")
public static let options = HTTPMethod(rawValue: "OPTIONS")
public static let patch = HTTPMethod(rawValue: "PATCH")
public static let post = HTTPMethod(rawValue: "POST")
public static let put = HTTPMethod(rawValue: "PUT")
public static let trace = HTTPMethod(rawValue: "TRACE")
public let rawValue: String
public init(rawValue: String) {
self.rawValue = rawValue
}
}
它里面的這些值可以被作為方法參數(shù)傳遞給 AF.request
API 使用:
AF.request("https://httpbin.org/get")
AF.request("https://httpbin.org/post", method: .post)
AF.request("https://httpbin.org/put", method: .put)
AF.request("https://httpbin.org/delete", method: .delete)
需要記住的很重要的一點是斗蒋,不同的網(wǎng)絡請求方式(HTTP methods)會有不同的語義捌斧,還會根據(jù)服務器的不同要求進行相應的參數(shù)編碼。比如泉沾,URLSession
和 Alamofire
都不支持往 GET
的請求體里插入數(shù)據(jù)(passing body data)(那樣 是 POST 的做法)捞蚂,那樣做的話會報錯。
Alamofire 還提供了一個 URLRequest
的拓展跷究。里面的 httpMethod
屬性起到了橋接的作用姓迅,這個屬性把 URLRequest
中的 String
類型的 HTTP 請求方式(HTTP Methods) 轉(zhuǎn)變?yōu)?Alamofire的 HTTPMethod
類型:
public extension URLRequest {
/// Returns the `httpMethod` as Alamofire's `HTTPMethod` type.
var method: HTTPMethod? {
get { return httpMethod.flatMap(HTTPMethod.init) }
set { httpMethod = newValue?.rawValue }
}
}
如果你想使用一個 Alamofire 的 HTTPMethod
不支持的請求方式色冀,你可以拓展 HTTPMethod
來添加你自己的請求方式:
extension HTTPMethod {
static let custom = HTTPMethod(rawValue: "CUSTOM")
}
設置其他的 URLRequest
的屬性(Setting Other URLRequest
Properties)
Alamofire 創(chuàng)建網(wǎng)絡請求的時候提供了最通用的自定義請求參數(shù)潭袱,但是柱嫌,有時候這些默認的參數(shù)并不能滿足需求。通過傳入各種參數(shù)的方式創(chuàng)建請求的時候屯换,可以使用 RequestModifier
閉包來修改這個正在創(chuàng)建的請求编丘。舉個例子,可以設置這個請求的超時時間(URLRequest
'S timeoutInterval
)為5s彤悔,我們利用這個閉包(closure)來這樣修改:
AF.request("https://httpbin.org/get", requestModifier: { $0.timeoutInterval = 5 }).response(...)
RequestModifier
也可以使用尾隨閉包的語法形式:
AF.request("https://httpbin.org/get") { urlRequest in
urlRequest.timeoutInterval = 5
urlRequest.allowsConstrainedNetworkAccess = false
}
.response(...)
RequestModifier
僅僅適用于通過 URL
和自定義參數(shù)創(chuàng)建請求的時候(譯者:上面第一個版本的請求)嘉抓,并不適用于直接從 URLRequestConvertible
里面的值們來提供參數(shù)值的那種創(chuàng)建請求的方式(譯者:上面第二個版本的請求),因為第二個版本封裝起來的那些值應該提供所有的請求所需的參數(shù)值晕窑。另外抑片,一旦但多數(shù)的網(wǎng)絡請求需要在創(chuàng)建的時候進行修改的話,那么還是推薦使用 URLRequestConvertible
(譯者:第二種高級抽象出來的類型提供所有參數(shù)杨赤,在創(chuàng)建的時候就可以修改敞斋,第一種采用閉包,是創(chuàng)建完了之后對請求進行的配置)疾牲。你可以更多的在這里進行了解: Advanced Usage documentation植捎。
請求參數(shù)和參數(shù)編碼(Request Parameters and Parameter Encoders)
Alamofire 支持傳遞任何 Encodable
類型的數(shù)據(jù)作為網(wǎng)絡請求的參數(shù)。這些參數(shù)會被一個符合 ParmeterEncoder
協(xié)議(protocol)的類型處理之后進行傳遞阳柔,添加到網(wǎng)絡請求之中济锄,然后通過網(wǎng)絡發(fā)送出去。Alamofier 里面有兩個符合 ParameterEncoder
的類型霍转,他們分別是:JSONParameterEncoder
和 URLEncodedFormParameterEncoder
谴忧。這倆類型涵蓋了幾乎所有的現(xiàn)代網(wǎng)絡請求服務所需的參數(shù)編碼方式(XML的編碼方式就作為練習交給使用我們的老鐵們了)委造。
struct Login: Encodable {
let email: String
let password: String
}
let login = Login(email: "test@test.test", password: "testPassword")
AF.request("https://httpbin.org/post",
method: .post,
parameters: login,
encoder: JSONParameterEncoder.default).response { response in
debugPrint(response)
}
第一種參數(shù)編碼方式(URLEncodedFormParameterEncoder)
URLEncodedFormParameterEncoder
類型的編碼器將值編碼成url編碼(url-encoded)用以設置或者添加到現(xiàn)有的URL查詢字符串中(譯者:GET)妇穴,或者設置為HTTP請求的請求體(HTTP body)(譯者:POST)。通過設置編碼器的 destination
來控制被編碼后字符串設置到哪里(譯者:URL中或者HTTP body中)。URLEncodedFormParameterEncoder.Destination
這個枚舉有以下幾個枚舉值:
-
.methodDependent
- 把編碼過后的結果設置到現(xiàn)有的.get
赞警,.head
,.delete
類型的請求的URL查詢字符串中笤虫,以及其他的HTTP請求類型的請求體之中(HTTP body)。 -
.queryString
- 把編碼過后的字符串設置或者添加到網(wǎng)絡請求的這個URL查詢字符串中。 -
.httpBody
- 把編碼過后的字符串設置到 HTTP 請求體中去(HTTP body)罚拟。
譯者:第一種是根據(jù)情況自動選擇,第二種是與 GET 相同類別的請求阻逮,第三種是與 POST 相同類型的請求
對于使用HTTP請求體(HTTP body)的網(wǎng)絡請求,如果HTTP頭(HTTP header)中的 Content-Type
沒有被設置過,那么就會被設置成 application/x-www-form-urlencoded; charset=utf-8
在 Alamofire 內(nèi)部的實現(xiàn)中与柑,URLEncodedFormParameterEncoder
使用了 URLEncodedFormEncoder
去真正的執(zhí)行把一個 Encodable
類型的數(shù)據(jù)編碼成URL編碼的字符串。這個編碼器可以用于各種類型的自定義的類型們脯倚,包括有 Array
使用 ArrayEncoding
,Bool
使用 BoolEncoding
乳丰,Data
使用 DataEncoding
汞斧,Date
使用 DateEncoding
,編碼鍵(keys)使用 KeyEncoding
庙睡, 空格(spaces)使用 SpaceEncoding
雕擂。
URL編碼參數(shù)的GET請求(GET Request With URL-Encoded Parameters):
let parameters = ["foo": "bar"]
// All three of these calls are equivalent
AF.request("https://httpbin.org/get", parameters: parameters) // encoding defaults to `URLEncoding.default`
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/get", parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .methodDependent))
// https://httpbin.org/get?foo=bar
URL編碼參數(shù)的POST請求(POST Request With URL-Encoded Parameters):
let parameters: [String: [String]] = [
"foo": ["bar"],
"baz": ["a", "b"],
"qux": ["x", "y", "z"]
]
// All three of these calls are equivalent
AF.request("https://httpbin.org/post", method: .post, parameters: parameters)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: URLEncodedFormParameterEncoder(destination: .httpBody))
// HTTP body: "qux[]=x&qux[]=y&qux[]=z&baz[]=a&baz[]=b&foo[]=bar"
配置編碼過后的值的排序
從 Swift 4.2 開始,Swift 的 Dictionary
類型所使用的哈希算法會在運行時會產(chǎn)生隨機的內(nèi)部排序,這就使得每次啟動應用程序可能會有所不同。這樣會導致編碼過后的參數(shù)順序有所改變瓷马,從而影響緩存和其他行為。URLEncodedFormEncoder
將會對編碼過后的鍵值對(key-value pairs)進行排序。這將會為所有 Encodable
類型提供一個恒定的順序的輸出,他可能會與該類型實際的編碼順序不符(譯者:自己寫的參數(shù)的順序痕届,當然這個順序在 Dictionary
是隨機的,和編碼過后被排序過得參數(shù)順序可能會不匹配)。你可以通過設置 alphabetizeKeyValuePairs
為 false
來返回實際的參數(shù)順序申屹,盡管這樣做的話可能會擁有隨機的 Dictionary
順序。
你可以創(chuàng)建一個你自己的 URLEncodedFormParameterEncoder
在傳遞進來 URLEncodedFormEncoder
的初始化方法中指定你所期望的 alphabetizeKeyValuePairs
的值:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(alphabetizeKeyValuePairs: false))
配置 Array
參數(shù)的編碼(Configuring the Encoding of Array
Parameters)
由于沒有發(fā)布過任何有關如何編碼集合類型的規(guī)范,Alamofire 依照慣例,將 []
添加到數(shù)組名字的后面(foo[]=1&foo[]=2
)瑞驱,對于嵌套字典, 則將被方括號包圍的key添加到的后面(foo[bar]=baz
)。
URLEncodedFormEncoder.ArrayEncoding
這個枚舉提供了以下的編碼 Array
參數(shù)的方式:
-
.brackets
- 為每一個數(shù)組里面的值添加一個空的方括號的集合晒奕,這個也是默認的選項砰盐。 -
.noBrackets
- 沒有添加方括號楞卡,按照原樣進行編碼霜运。
Alamofire 默認的使用 .brackets
去編碼 Array
, 這樣的話 foo = [1, 2]
就會被編碼成 foo[]=1&foo[]=2
蒋腮。
使用 .noBrackets
編碼的話就會把 foo=[1, 2]
編碼成 foo=1&foo=2
。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
藕各,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 ArrayEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(arrayEncoding: .noBrackets))
配置 Bool
類型參數(shù)的編碼方式(Configuring the Encoding of Bool Parameters)
URLEncodedFormEncoder.BoolEncoding
枚舉提供了以下幾種用于編碼 Bool
類型參數(shù)的方式:
-
.numeric
- 把true
編碼為1
激况,把false
編碼為0
。這也是默認的方式蹬挤。 -
.literal
- 把true
和false
編碼為文字蹋嵌。
Alamofire 默認的使用 .numeric
的這種方式慧起。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
馅袁,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 BoolEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(boolEncoding: .numeric))
配置 Data
類型的參數(shù)編碼
DataEncoding
包括以下幾種編碼 Data
參數(shù)類型的方式:
-
.deferredToData
- 使用Data
的本地的Encodable
支持削茁。 -
.base64
- 把Data
編碼為 Base 64 編碼格式的字符串捍岳。這是默認的方式搀绣。 -
.custom((Data) -> throws -> String)
- 使用提供的閉包(closure)進行編碼贸毕。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 DataEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dataEncoding: .base64))
配置 Date
類型的參數(shù)編碼:
鑒于有大量的方法可以吧 Date
編碼稱為 String
,DateEncoding
包括了以下這些方式來編碼 Date
參數(shù):
-
.deferredToDate
- 使用Date
的本地的Encodable
支持卧晓,這是默認的方式桐愉。 -
.secondsSince1970
- 把Date
編碼為從1970年1月1日的午夜開始到現(xiàn)在的秒數(shù)。 -
.millisecondsSince1970
- 把Date
編碼為從1970年1月1日的午夜開始到現(xiàn)在的毫秒數(shù)亿眠。 -
.iso8610
- 根據(jù) ISO 8610 和 RFC3339 標準對Date
進行編碼碎罚。 -
formatted(DateFormatter)
- 使用給定的DateFormatter
對Date
進行編碼憔购。 -
custom((Date) -> throws -> String)
- 使用給定的閉包(closure)對Date
進行編碼。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
先馆,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 DateEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(dateEncoding: .iso8601))
配置鍵的編碼方式(Configuring the Encoding of Coding Keys)
由于參數(shù)鍵的樣式多鐘多樣梅惯,KeyEncoding
提供以下方法去編碼使用駝峰命名法(lowerCamelCase)的鍵:
-
.useDefaultKeys
- 使用每種類型指定的鍵。這個是默認的方式仿野。 -
.convertToSnakeCase
- 把鍵編碼為下劃線(譯者:snake是蛇形)樣式:oneTwoThree
變成one_two_three
铣减。 -
.convertToKebabCase
- 把鍵編碼為橫線(譯者:kebab是烤串)樣式:oneTwoThree
變成one-two-three
。 -
.capitalized
- 僅僅大寫第一個字母脚作,又叫做UpperCamelCase
:oneTwoThree
變成OneTwoThree
葫哗。 -
.uppercased
- 大寫所有字母:oneTwoThree
變成ONETWOTHREE
。 -
lowercased
- 小寫所有字母:oneTwoThree
變成onetwothree
球涛。 -
.custom((String) -> String)
- 使用給定的閉包(closure)進行編碼劣针。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 KeyEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(keyEncoding: .convertToSnakeCase))
配置空格編碼(Configuring the Encoding of Spaces)
比較早的編碼器們使用 +
去編碼空格亿扁,許多服務器至今仍然希望使用這種編碼而不是使用現(xiàn)代的百分號編碼酿秸,因此 Alamofire 包涵了以下的方式對空格進行編碼:
-
.percentEscaped
- 通過應用標磚的百分比轉(zhuǎn)碼對空格字符進行編碼。" "
被編碼成"%20"
魏烫。這個是默認的方式。 -
.plusReplaced
- 把" "
替換+
肝箱。" "
被編碼成+
哄褒。
你可以創(chuàng)建你自己的 URLEncodedFormParameterEncoder
,然后在需要傳遞 URLEncodedFormEncoder
的初始化方法中指定 SpaceEncoding
:
let encoder = URLEncodedFormParameterEncoder(encoder: URLEncodedFormEncoder(spaceEncoding: .plusReplaced))
第二種編碼方式(JSONParameterEncoder)
JSONParameterEncoder
利用Swift的 JSONEncoder
對Encodable
類型的值(values)進行編碼煌张,然后把編碼后的結果設置到 URLRequest
的 httpBody
中呐赡。如果 HTTP header中的 Content-Type
沒有設置過的話,會被設置成 aplication/json
骏融。
發(fā)送一個JSON編碼(JSON-Encoded)參數(shù)的網(wǎng)絡請求
let parameters: [String: [String]] = [
"foo": ["bar"],
"baz": ["a", "b"],
"qux": ["x", "y", "z"]
]
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.prettyPrinted)
AF.request("https://httpbin.org/post", method: .post, parameters: parameters, encoder: JSONParameterEncoder.sortedKeys)
// HTTP body: {"baz":["a","b"],"foo":["bar"],"qux":["x","y","z"]}
配置一個自定義的 JSONEncoder
你可以通過傳遞一個你配置好的 JSONEncoder
實例來自定義 JSONParameterEncoder
的行為:
let encoder = JSONEncoder()
encoder.dateEncoding = .iso8601
encoder.keyEncodingStrategy = .convertToSnakeCase
let parameterEncoder = JSONParameterEncoder(encoder: encoder)
手動為 URLRequest
參數(shù)進行編碼
ParameterEncoder
的API們也可以用于Alamofire之外直接對 URLRequest
進行參數(shù)編碼链嘀。
let url = URL(string: "https://httpbin.org/get")!
var urlRequest = URLRequest(url: url)
let parameters = ["foo": "bar"]
let encodedURLRequest = try URLEncodedFormParameterEncoder.default.encode(parameters,
into: urlRequest)
HTTP頭(HTTP Headers)
Alamofire 擁有自己的的 HTTPHeaders
類型萌狂,他是一個保持原有順序并且不區(qū)分大小寫的 HTTP頭的鍵值對表示。 HTTPHeader
類型封裝了一個單獨的鍵值對并且為通用的HTTP頭(headers)提供了許多種靜態(tài)的值怀泊。
為一個 Request
添加一個自定義的 HTTPHeaders
就像給一個 request
的方法傳遞一個值那么簡單:
let headers: HTTPHeaders = [
"Authorization": "Basic VXNlcm5hbWU6UGFzc3dvcmQ=",
"Accept": "application/json"
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
HTTPHeaders
也可以使用一個包含有 HTTPHeader
類型值的數(shù)組來構建:
let headers: HTTPHeaders = [
.authorization(username: "Username", password: "Password"),
.accept("application/json")
]
AF.request("https://httpbin.org/headers", headers: headers).responseJSON { response in
debugPrint(response)
}
對于 HTTP 頭來說茫藏,沒有變的是,推薦把他們設置到
URLSessionConfiguration
霹琼,這樣他們就可以提供給任何通過基礎的URLSession
所創(chuàng)建的URLSessionTask
之中了务傲。更多的信息請看會話設置(Session Configurations)章節(jié)。
默認的Alamofire Session
為每個 Request
提供了默認的頭部信息(headers)集合枣申,他們是:
-
Accept-Encoding
售葡,根據(jù)RFC 7230 §4.2.3,默認的值是br;q=1.0, gzip;q=0.8, deflate;q=0.6
忠藤。 -
Accept-Language
挟伙,根據(jù)RFC 7231 §5.3.5,默認的是系統(tǒng)上首選的6種語言模孩,格式就像是:en;q=1.0
漫试。 -
User-Agent
,根據(jù)RFC 7231 §5.5.3妒潭,包含有當前應用的版本信息着帽,舉個例子:iOS Example/1.0 (com.alamofire.iOS-Example; build:1; iOS 13.0.0) Alamofire/5.0.0
如果你想自定義這些頭部信息(headers),你應該去創(chuàng)建一個自定義的 URLSessionConfiguration
祭芦,更新 defaultHTTPHeaders
屬性并將配置應用于新的 Session
實例筷笨。使用 URLSessionConfiguration.af.default
去自定義你的配置并且保留 Alamofire 默認的頭部信息(headers)。
響應驗證(Response Validation)
Alamofire 默認的會把所有已經(jīng)完成的網(wǎng)絡請求都視為是成功的龟劲,忽略服務端響應的內(nèi)容胃夏。如果響應的狀態(tài)碼(status code)或者 MIME類型不能被接受(unacceptable)(譯者:異常狀態(tài)碼或類型錯誤啥的)的話可以在響應處理(response handler)生成錯誤之前調(diào)用 validate()
函數(shù)。
自動校驗(Automatic Validation)
validate()
這個API自動驗證響應狀態(tài)碼的區(qū)間是 200..<300
昌跌,如果提供了請求的 Accept
頭的話仰禀,請求的 Accept
頭的信息要與響應的 Content-Type
相匹配。
AF.request("https://httpbin.org/get").validate().responseJSON { response in
debugPrint(response)
}
手動校驗(Manual Validatin)
AF.request("https://httpbin.org/get")
.validate(statusCode: 200..<300)
.validate(contentType: ["application/json"])
.responseData { response in
switch response.result {
case .success:
print("Validation Successful")
case let .failure(error):
print(error)
}
}
響應處理方式(Response Handling)
Alamofire 的 DataRequest
和 DownloadRequest
都有相應的響應類型:DataResponse<Success, Failure: Error>
和 DownloadResponse<Success, Failure: Error>
蚕愤。他們倆都有著相同的組成:一個序列化類型和一個錯誤類型答恶。默認情況下,所有的響應值都會產(chǎn)生錯誤類型(即:DataResponse<Success, AFError>
)萍诱。Alamofire 在公開的 API 中使用更簡單的 AFDataResponse<Success>
和 AFDownloadResponse<Success>
悬嗓,他們都包涵有 AFError
類型。 UploadRequest
是 DataRequest
的子類裕坊,使用同樣的 DataResponse
類型包竹。
處理 Alamofire 的 DataRequest
或者 UploadRequest
所產(chǎn)生的 DataResponse
涉及到將諸如 responseJSON
這樣的響應處理 鏈接 到 DataRequest
:
AF.request("https://httpbin.org/get").responseJSON { response in
debugPrint(response)
}
在上面的例子中,responseJSON
處理程序被添加到了 DataRequest
上,在 DataRequest
完成的時候執(zhí)行一次處理程序周瞎。傳遞給處理程序的是一個閉包(closure)苗缩,這個閉包接收一個 AFDataResponse<Any>
類型的值,這個值是由響應屬性中的 JSONRespnseSerializer
所制造出來的声诸。
這個閉包(closure)作為回調(diào)(callback)被添加上去以便在接收到響應的時候去執(zhí)行處理酱讶,這樣做比阻塞執(zhí)行來等待服務器的響應要好的多。請求的結果僅僅在響應閉包(closure)的范圍內(nèi)有效双絮。任何取決于響應的或者從服務器接收的數(shù)據(jù)的處理都要在響應閉包(closure)中完成浴麻。
在 Alamofire 下的網(wǎng)絡請求都是異步的。異步編程可能使不熟悉這個概念的程序員感到沮喪囤攀,但是異步編程的 好處 是非常多的软免。
Alamofire 中包涵了6種不同的默認的數(shù)據(jù)響應處理程序,包括:
// Response Handler - Unserialized Response
func response(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse<Data?>) -> Void) -> Self
// Response Serializer Handler - Serialize using the passed Serializer
func response<Serializer: DataResponseSerializerProtocol>(queue: DispatchQueue = .main,
responseSerializer: Serializer,
completionHandler: @escaping (AFDataResponse<Serializer.SerializedObject>) -> Void) -> Self
// Response Data Handler - Serialized into Data
func responseData(queue: DispatchQueue = .main,
completionHandler: @escaping (AFDataResponse<Data>) -> Void) -> Self
// Response String Handler - Serialized into String
func responseString(queue: DispatchQueue = .main,
encoding: String.Encoding? = nil,
completionHandler: @escaping (AFDataResponse<String>) -> Void) -> Self
// Response JSON Handler - Serialized into Any Using JSONSerialization
func responseJSON(queue: DispatchQueue = .main,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (AFDataResponse<Any>) -> Void) -> Self
// Response Decodable Handler - Serialized into Decodable Type
func responseDecodable<T: Decodable>(of type: T.Type = T.self,
queue: DispatchQueue = .main,
decoder: DataDecoder = JSONDecoder(),
completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self
沒有任何一個響應處理程序?qū)姆掌骰貋淼?HTTPURLResponse
執(zhí)行校驗焚挠。
舉個例子:響應的狀態(tài)碼在
400..<500
和500..<600
的范圍內(nèi)并不會自動觸發(fā)任何Error
膏萧。Alamofire 采用響應校驗(Response Validation)(上文提到的) 方式來實現(xiàn)校驗。(譯者:所以處理函數(shù)中并不做任何響應的校驗)
響應處理程序(Response Handler)
response
處理程序并不校驗任何響應數(shù)據(jù)蝌衔。他僅僅直接從 URLSessionDelegate
轉(zhuǎn)發(fā)所有的信息(infomation)榛泛。這就是 Alamofire 等效于使用 cURL
去執(zhí)行 Request
。
AF.request("https://httpbin.org/get").response { response in
debugPrint("Response: \(response)")
}
我們強烈建議您去
Response
和Result
類型的其他的響應序列化工具(譯者:我的感覺是不建議直接用response噩斟,因為提供了6個方法曹锨,建議使用其他更具體好用的方法吧)。
響應 Data 數(shù)據(jù)的處理程序(Response Data Handler)
responseData
處理程序使用 DataResponseSerializer
去提取和校驗服務器返回的 Data
數(shù)據(jù)剃允。如果沒有錯誤發(fā)生并且返回了 Data
數(shù)據(jù)沛简。那么響應中的 Result
將會是 .success
的并且它里面的 value
會變成服務器返回的 Data
數(shù)據(jù)。
AF.request("https://httpbin.org/get").responseData { response in
debugPrint("Response: \(response)")
}
響應字符數(shù)據(jù)的處理程序(Response String Handler)
responseString
處理程序使用了 StringResponseSerializer
去把服務器返回的 Data
數(shù)據(jù)轉(zhuǎn)換成指定編碼的 String
斥废。如果沒有錯誤產(chǎn)生并且服務端返回的 數(shù)據(jù)成功的被序列化為 String
椒楣,相應的結果將會是 .success
并且結果的 value
值將會是 String
類型。
AF.request("https://httpbin.org/get").responseString { response in
debugPrint("Response: \(response)")
}
如果沒有指定任何編碼方式牡肉,Alamofire 將會使用服務端返回的
HTTPURLResponse
中指定的文本編碼捧灰。如果無法根據(jù)服務器響應確定文本編碼,默認的是采用.isoLatin1
统锤。
響應JSON數(shù)據(jù)的處理程序(Response JSON Handler)
responseJSON
處理程序利用 JSONResponseSerializer
去將服務端返回的 Data
數(shù)據(jù)轉(zhuǎn)換成使用指定 JSONSerialization.ReadingOptions
的 Any
類型的數(shù)據(jù)毛俏。如果沒有錯誤發(fā)生并且成功的將服務端的數(shù)據(jù)序列化成了JSON對象(JSON object),那么響應 AFResult
將會是 .sucess
并且他的 value
將會是 Any
類型饲窿。
AF.request("https://httpbin.org/get").responseJSON { response in
debugPrint("Response: \(response)")
}
respnseJSON
中使用的 JSON 序列化是使用的Foundation
框架中的JSONSerialization
來完成處理的拧抖。
響應 Decodable
數(shù)據(jù)的處理程序(Response Decodable
Handler)
responseDecodable
數(shù)據(jù)處理程序使用 DecodableResponseSerializer
去將服務端返回的 Data
數(shù)據(jù)轉(zhuǎn)換成傳參進來的使用指定 DataDecoder
(一個可以從數(shù)據(jù)(Data
)解碼的解碼器(Decoder
)的協(xié)議) 的 Decodable
類型數(shù)據(jù)。如果沒有錯誤產(chǎn)生并且成功的將服務端返回的數(shù)據(jù)解碼成了一個 Decodable
類型免绿,那么響應的 Result
將會是 .success
的并且 他的 value
將會是傳參進來的類型。
struct HTTPBinResponse: Decodable { let url: String }
AF.request("https://httpbin.org/get").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint("Response: \(response)")
}
鏈式的響應處理程序(Chained Response Handlers)
響應處理程序也可以被串聯(lián)起來:
Alamofire.request("https://httpbin.org/get")
.responseString { response in
print("Response String: \(response.value)")
}
.responseJSON { response in
print("Response JSON: \(response.value)")
}
很重要的一點是擦盾,如果在同一個
Request
使用多重響應處理程序的話嘲驾,需要服務器對返回數(shù)據(jù)多次序列化淌哟,每個響應處理程序處理一次。最好不要在同一個Request
上使用多重響應處理程序辽故,特別是在生產(chǎn)環(huán)境中徒仓。這種做做僅僅應該在開發(fā)環(huán)境或者沒有其他的更好的選擇的情況下去做。
相應處理程序隊列(Response Handler Queue)
給響應處理程序傳遞的閉包(closures)默認是在 .main
隊列上執(zhí)行的誊垢,但是也可以指定一個 DispatchQueue
給需要執(zhí)行的閉包(closure)掉弛。事實上,序列化的工作(把 Data
數(shù)據(jù)轉(zhuǎn)換成其他類型的數(shù)據(jù))總是在一個后臺隊列(background queue)中執(zhí)行的喂走。
let utilityQueue = DispatchQueue.global(qos: .utility)
AF.request("https://httpbin.org/get").responseJSON(queue: utilityQueue) { response in
print("Executed on utility queue.")
debugPrint(response)
}
響應的緩存(Response Caching)
響應緩存是由 URLCache
在系統(tǒng)級別進行處理的殃饿。他提供了一個內(nèi)存(in-memory)和磁盤(on-disk)緩存的結合體,使您可以操控內(nèi)存(in-memory)和磁盤(on-disk)部分的大小芋肠。
Alamofire默認的使用
URLCache.shared
這個實例進行自定義的URLCache
實例的使用乎芳,請看會話配置(Session Configuration)章節(jié)。
認證方式(Authentication)
認證方式(Authentication)是由 URLCredential
和 URLAuthenticationChallenge
在系統(tǒng)框架級別進行操作的帖池。
這些認證方式的 API 適用于提示授權的服務器奈惑,并非一般用于需要
Authenticate
(譯者:身份驗證) 和 等效的請求頭的服務器。
支持的驗證方式(Supported Authentication Schemes)
HTTP Basic 授權方式(HTTP Basic Authentication)
當使用 URLAuthenticationChallenge
質(zhì)詢的時候睡汹,在適當?shù)臅r候Request
上的 authenticate
方法會自動提供 URLCredential
:
let user = "user"
let password = "password"
AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(username: user, password: password)
.responseJSON { response in
debugPrint(response)
}
URLCredential
授權方式(Authentication with URLCredential
)
let user = "user"
let password = "password"
let credential = URLCredential(user: user, password: password, persistence: .forSession)
AF.request("https://httpbin.org/basic-auth/\(user)/\(password)")
.authenticate(with: credential)
.responseJSON { response in
debugPrint(response)
}
需要注意的很重要的一點是肴甸,當你使用
URLCredential
來進行認證的時候,如果服務器發(fā)出了質(zhì)詢囚巴,那么底層的URLSession
實際上最終會發(fā)出兩個請求(requests)原在。第一個請求將會不包括可能觸發(fā)服務器質(zhì)詢的憑據(jù)(credential)。Alamofire來接收這個服務器的質(zhì)詢文兢,并把憑證(credential)加上去晤斩,再由底層的的URLSession
重新發(fā)送請求(request)。
手動授權(Manual Authentication)
如果你要與一個始終需要 Authenticate
或者類似的請求頭的 API 通信而沒有提示的時候姆坚,你可以手動的加上:
let user = "user"
let password = "password"
let headers: HTTPHeaders = [.authorization(username: user, password: password)]
AF.request("https://httpbin.org/basic-auth/user/password", headers: headers)
.responseJSON { response in
debugPrint(response)
}
但是澳泵,必須作為所有請求的一部分的請求頭(headers)通常更好的被處理為自定義的 URLSessionConfiguration
的一部分,或者使用一個 RequestAdapter
兼呵。(譯者注:這些在高級用法中有提到)
下載數(shù)據(jù)到文件(Downloading Data to a File)
除了把獲取到的數(shù)據(jù)放入內(nèi)存兔辅,Alamofire 還提供了 Session.download
,DownloadRequest
击喂,和 DownloadResponse<Success, Failure: Error>
這些 API 去方便的下載數(shù)據(jù)到磁盤维苔。下載到內(nèi)存的行為非常適合像大多數(shù) JSON API 的很小的響應信息,而獲取大的資源像是圖片和視頻懂昂,就應該下載到磁盤以緩解應用的內(nèi)存空間介时。
AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
DownloadRequest
具有與DataRequest
相同的大多數(shù)的響應處理程序(response
handlers)。但是,由于他把數(shù)據(jù)下載到磁盤沸柔,序列化響應會涉及到從磁盤讀取數(shù)據(jù)循衰,這樣也可能導致往內(nèi)存中讀取了大量的數(shù)據(jù)。在涉設計你自己的數(shù)據(jù)下載處理的時候要記住這些褐澎,這很重要会钝。
文件下載的位置(Download File Destination)
所有下載的數(shù)據(jù)最初都存放在系統(tǒng)的臨時目錄里(temporary directory)。這些數(shù)據(jù)最終將會被系統(tǒng)在某個時間點刪除掉工三,因此如果有些情況需要這些文件存在的時間更長一些的話迁酸,把他們移動到某個其他的地方是很重要的。
你可以提供一個 Destination
閉包(closure)去把文件從臨時文件目錄移動到最終的位置上去俭正。在臨時文件被真正的移動到 destinationURL
之前奸鬓,閉包(closure)中指定的 Options
會被執(zhí)行,目前支持的兩種 Options
是:
-
. createIntermediateDirectories
- 如果指定目錄段审,則為目標目錄創(chuàng)建中間目錄全蝶。 -
.removePreviousFile
- 如果指定,則從目標目錄中刪除之前的文件寺枉。
let destination: DownloadRequest.Destination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("image.png")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
AF.download("https://httpbin.org/image/png", to: destination).response { response in
debugPrint(response)
if response.error == nil, let imagePath = response.fileURL?.path {
let image = UIImage(contentsOfFile: imagePath)
}
}
你也可以使用建議的下載位置的 API:
let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)
AF.download("https://httpbin.org/image/png", to: destination)
下載進度(download Progress)
很多時候抑淫,給用戶報告下載進度是很有用的。任何的 DownloadRequest
都可以利用 downloadProgress
API 來報告下載進度姥闪。
AF.download("https://httpbin.org/image/png")
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
僅當服務器返回
Content-Length
頭的時候始苇,URLSession
的進度報告相關的 API 才起作用,對于 ALamofire 也是這樣的筐喳。沒有這個頭(header)的話催式,進度將停留在0.0
,下載完成避归,進度會跳到1.0
荣月。
downloadProgress
API 也可以傳入一個 queue
參數(shù)來定義哪一個 DispatchQueue
是下載進度閉包(closure)所調(diào)用的的所在。
let progressQueue = DispatchQueue(label: "com.alamofire.progressQueue", qos: .utility)
AF.download("https://httpbin.org/image/png")
.downloadProgress(queue: progressQueue) { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
取消和重新下載(Canceling and Resuming a Download)
除了所有的 Request
類都有 cancel()
API 之外梳毙,DownloadRequest
還可以生成恢復數(shù)據(jù)(resume data)哺窄,這些恢復數(shù)據(jù)可以被用來在稍后的時候重新下載數(shù)據(jù)。這個 API 有兩種形式:cancel(producingResumeData: Bool)
可以控制是否生成恢復數(shù)據(jù)账锹,但是他僅僅對 DownloadResponse
有用萌业;cancel(byProducingResumeData:(_ resumeData: Data?) -> Void)
有著相同的作用,但是他可以讓恢復數(shù)據(jù)在完成處理程序(completion handler)中可用奸柬。
如果一個 DownloadRequest
被取消了或者被中斷了生年,底層的 URLSessinDownloadTask
可能會生成回復數(shù)據(jù)。如果生成了恢復數(shù)據(jù)廓奕,這個恢復數(shù)據(jù)可以再次被用來在中斷的地方重新開始 DownloadRequest
抱婉。
極其重要: 在蘋果平臺的某些版本(iOS10 - 10.2档叔,macOS10.12-10.12.2, tvOS10-10.1蒸绩,watchOS3-3.1.1 )中蹲蒲,
resumeData
在后臺的URLSessionConfiguration
中是損壞的。在底層的resumeData
生成邏輯中存在錯誤侵贵,錯誤的數(shù)據(jù)被寫入,導致了始終無法通過resumeData
重新進行下載缘薛。關于更多的這個bug的信息和可能的解決辦法窍育,請看 Stack Overflow post。
var resumeData: Data!
let download = AF.download("https://httpbin.org/image/png").responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
// download.cancel(producingResumeData: true) // Makes resumeData available in response only.
download.cancel { data in
resumeData = data
}
AF.download(resumingWith: resumeData).responseData { response in
if let data = response.value {
let image = UIImage(data: data)
}
}
上傳數(shù)據(jù)到服務器(Uploading Data to a Server)
當發(fā)送相對少量的使用 JSON 或者 URL 編碼的參數(shù)到服務器的時候宴胧,request()
APIs 通常就夠用了漱抓。如果你需要發(fā)送從內(nèi)存中、通過文件 URL
恕齐、或者 InputStream
來的大量的 Data
的時候乞娄,upload()
APIs 可能是你想要使用的。
上傳數(shù)據(jù)(Uploading Data)
let data = Data("data".utf8)
AF.upload(data, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳文件(Uploading a File)
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post").responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳多部分表格數(shù)據(jù)(Uploading Multipart Form Data)
AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(Data("one".utf8), withName: "one")
multipartFormData.append(Data("two".utf8), withName: "two")
}, to: "https://httpbin.org/post")
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
上傳進度(Upload Progress)
當你的用戶正在等待他們上傳數(shù)據(jù)完成的時候显歧,有時候展示給用戶上傳進度對于他們是很便利的仪或。任何的 UploadRequest
使用 uploadProgress
和 downloadProgress
的時候都可以報告上傳數(shù)據(jù)的進度和響應數(shù)據(jù)下載的進度。
let fileURL = Bundle.main.url(forResource: "video", withExtension: "mov")
AF.upload(fileURL, to: "https://httpbin.org/post")
.uploadProgress { progress in
print("Upload Progress: \(progress.fractionCompleted)")
}
.downloadProgress { progress in
print("Download Progress: \(progress.fractionCompleted)")
}
.responseDecodable(of: HTTPBinResponse.self) { response in
debugPrint(response)
}
從服務器來的流式傳輸數(shù)據(jù)(Streaming Data from a Server)
使用流傳輸而不是積累不斷接收到的數(shù)據(jù)士骤,可以更好的服務于長時間下載大型的文件或者連接服務器范删。Alamofire 提供了 DataStreamRequest
這個類型以及相關的 API 去處理這種用法。盡管這樣就提供了好多像其他的 Request
一樣的 API拷肌,但是它仍然有幾個主要的區(qū)別到旦。最明顯的, DataStreamRequest
不在內(nèi)存中積累數(shù)據(jù)或者將數(shù)據(jù)存入磁盤(disk)巨缘。相反的是添忘,它在數(shù)據(jù)到達的時候反復調(diào)用 responseStream
閉包(closures)。在連接完成或者收到錯誤的時候會再次調(diào)用相同的閉包若锁。
每個 Handler
閉包(closure)都捕獲一個 Stream
值搁骑,其中包括一個 Event
以及可以取消請求的 CancellationToken
。
public struct Stream<Success, Failure: Error> {
/// Latest `Event` from the stream.
public let event: Event<Success, Failure>
/// Token used to cancel the stream.
public let token: CancellationToken
/// Cancel the ongoing stream by canceling the underlying `DataStreamRequest`.
public func cancel() {
token.cancel()
}
}
一個 Event`` 就是一個代表兩種流狀態(tài)的
enum```拴清。
public enum Event<Success, Failure: Error> {
/// Output produced every time the instance receives additional `Data`. The associated value contains the
/// `Result` of processing the incoming `Data`.
case stream(Result<Success, Failure>)
/// Output produced when the instance has completed, whether due to stream end, cancellation, or an error.
/// Associated `Completion` value contains the final state.
case complete(Completion)
}
完成的時候靶病,Completion
值將會包含流結束時候的 DataStreamRequest
的狀態(tài)。
public struct Completion {
/// Last `URLRequest` issued by the instance.
public let request: URLRequest?
/// Last `HTTPURLResponse` received by the instance.
public let response: HTTPURLResponse?
/// Last `URLSessionTaskMetrics` produced for the instance.
public let metrics: URLSessionTaskMetrics?
/// `AFError` produced for the instance, if any.
public let error: AFError?
}
流數(shù)據(jù)(Streaming Data
)
可以想其他的 Alamofire 請求一樣去完成從服務器請求流數(shù)據(jù)口予,但是多了一個 Handler
閉包(closure)娄周。
func responseStream(on queue: DispatchQueue = .main, stream: @escaping Handler<Data, Never>) -> Self
提供的 queue
將會是 handler
閉包所在的位置。
AF.streamRequest(...).responseStream { stream in
switch stream.event {
case let .stream(result):
switch result {
case let .success(data):
print(data)
}
case let .complete(completion):
print(completion)
}
}
在上面的例子中處理
.failure
這種Result
的情況是不必要的沪停,接收Data
不可能是失敗的煤辨。
流式的字符串(Streaming String
s)
像流式 Data
一樣裳涛,String
可以添加 Handler
來處理流式字符串數(shù)據(jù)。
func responseStreamString(on queue: DispatchQueue = .main,
stream: @escaping StreamHandler<String, Never>) -> Self
String
值被解碼為 UTF8
众辨,這種解碼不會失敗端三。
AF.streamRequest(...).responseStreamString { stream in
switch stream.event {
case let .stream(result):
switch result {
case let .success(string):
print(string)
}
case let .complete(completion):
print(completion)
}
}
流式 Decodable
值(Streaming Decodable
值)
傳入的流式 Data
值可以使用 responseStreamDecodable
轉(zhuǎn)換成任意的 Decodable
。
func responseStreamDecodable<T: Decodable>(of type: T.Type = T.self,
on queue: DispatchQueue = .main,
using decoder: DataDecoder = JSONDecoder(),
preprocessor: DataPreprocessor = PassthroughPreprocessor(),
stream: @escaping Handler<T, AFError>) -> Self
解碼(Decoding)失敗并不會終止流鹃彻,而是在 Result
的 Output
中生成一個 AFError
郊闯。
AF.streamRequest(...).responseStreamDecodable(of: SomeType.self) { stream in
switch stream.event {
case let .stream(result):
switch result {
case let .success(value):
print(value)
case let .failure(error):
print(error)
}
case let .complete(completion):
print(completion)
}
}
生成一個輸入流(Producing an InputStream)
除了使用 StreamHandler
閉包處理傳入的 Data
之外, DataStreamRequest
可以生成一個可以讀取到達的字節(jié)的 InputStream
蛛株。
func asInputStream(bufferSize: Int = 1024) -> InputStream
通過這種方式創(chuàng)建的 InputStream
必須在讀取開始之前調(diào)用 open()
团赁,或者將其傳遞給自動打開流的 API。一旦從這個方法返回了 InputStream
谨履,這個方法的調(diào)用者有責任去保持 InputStream
存活欢摄,并且在讀取完之后調(diào)用 close()
。
let inputStream = AF.streamRequest(...)
.responseStream { output in
...
}
.asInputStream()
取消(Cancellation)
DataStreamRequest
們可以用4種方式來取消笋粟。第一種怀挠,像所有其他的 Alamofire 的 Request
一樣,DataStreamRequest
可以調(diào)用 cancel()
來取消底層(underlying)的任務(task)并且完成流害捕。
let request = AF.streamRequest(...).responseStream(...)
...
request.cancel()
第二種绿淋,DataStreamRequest
們可以在 DataStreamSerializer
發(fā)生錯誤的時候被自動的取消。這種行為默認是被禁止的但是可以通過 automaticallyCancelOnStreamError
這個參數(shù)在創(chuàng)建請求的時候允許這種行為吨艇。
AF.streamRequest(..., automaticallyCancelOnStreamError: true).responseStream(...)
第三種躬它,DataStreamRequest
們將會在 Handler
閉包(closure)拋出錯誤的時候被取消。之后东涡,這個錯誤會被存入請求之中并且在 Completion
值中可用冯吓。
AF.streamRequest(...).responseStream { stream in
// Process stream.
throw SomeError() // Cancels request.
}
最后一種,DataStreamRequest
們可以使用 Stream
值的 cancel()
方法來取消疮跑。
AF.streamRequest(...).responseStream { stream in
// Decide to cancel request.
stream.cancel()
}
統(tǒng)計指標(Statistical Metrics)
URLSessionTaskMetrics
Akanifure 為每一個 Request
收集 URLSessionTaskMetrics
组贺。URLSessionTaskMetrics
封裝了一些關于基礎的網(wǎng)絡連接和請求響應事件的奇妙的統(tǒng)計信息。
AF.request("https://httpbin.org/get").responseJSON { response in
print(response.metrics)
}
由于
FB7624529
祖娘,目前收集 watchOS 的URLSessionTaskMetrics
是不可用的失尖。
cURL 命令輸出(cURL Command Output)
調(diào)試平臺的錯誤可能讓人蛋疼,但是謝天謝地渐苏,Alamofire 的 Request
類型可以產(chǎn)生等效的 cURL 命令來方便調(diào)試掀潮。由于 Alamofire 的 Request
創(chuàng)建是異步的這個特性,這個API有同步(synchronous)的和一步的(asynchronous)兩個版本琼富。為了盡快的獲取 cURL 命令仪吧,你可以鏈接一個 CURLDescription
在request上:
AF.request("https://httpbin.org/get")
.cURLDescription { description in
print(description)
}
.responseJSON { response in
debugPrint(response.metrics)
}
這個就制造出來了:
$ curl -v \
-X GET \
-H "Accept-Language: en;q=1.0" \
-H "Accept-Encoding: br;q=1.0, gzip;q=0.9, deflate;q=0.8" \
-H "User-Agent: Demo/1.0 (com.demo.Demo; build:1; iOS 13.0.0) Alamofire/1.0" \
"https://httpbin.org/get"