前言
本篇是介绍Alamofire 的基本使用,对于还不会引入Alamofire的小伙伴可以看《73-Swift之Pods(CocoaPods)的Alamofire的引入的详细指导》。
Alamofire 是啥?
Alamofire是自2014年Swift 推出之后,AFNetworking的作者 [Mattt Thompson] 便提交了一个新的类似于AFNetworking 的网络基础框架,并且是专门使用最新的Swift 语言来编写的,其名为:Alamofire。
Alamofire 的优点
- 链式的请求/响应方法(GET&POST等)
- URLEncoding / JSONEncoding / PropertyListEncoding 参数编码
- 上传类型支持:文件(File )、数据(Data )、流(Stream)以及MultipartFormData
- 支持文件下载,下载支持断点续传
- 支持使用NSURLCredential进行身份验证
- HTTP响应验证validate()
Alamofire 对请求结果的解析方法提供如下
response 以请求DefaultDataResponse的对象返回请求结果。
responseData 这是将请求的结果以二进制流的形式解析。
responseJSON 这是将请求的结果以JSON的形式解析。
responseString 这是将请求的结果以字符串的形式解析。
responsePropertyList 这是将请求的结果以PLIST形式解析。
Alamofire 的GET请求方法和请求解析方法的介绍和使用
1、 无参数的Alamofire 的GET请求和解析方式的介绍
// MARK: Alamofire 的Get请求
func alamofireGet1() -> Void {
/**
该请求只有一个参数 'URLRequest',并返回请求对象(DataRequest)。我们可以处理请求对象(DataRequest)获取我们需要的数据。
*/
let dataRequest:DataRequest = Alamofire.request("http://www.jianshu.com/u/23dd8d9701bf")
// 输出请求返回的对象
print(dataRequest)
/**
输出结果
GET http://www.jianshu.com/u/23dd8d9701bf
*/
// 解析请求的对象
dataRequest.response { (DDResponse) in
// 获取请求的状态码
let stateCode = DDResponse.response?.statusCode
print(stateCode!)
// 获取请求的数据
print(DDResponse.data!)// 只输出数据有多少字节数
// 将数据转化为字符串
let dataStr = String.init(data: DDResponse.data!, encoding:String.Encoding.utf8)
print(dataStr!)
// TODO: 输出请求对象
let requestSwf = DDResponse.request
print(requestSwf!)
/*通过请求对象,我们可以获取请求的一系列信息*/
// 请求头文件
print(requestSwf?.allHTTPHeaderFields as Any)
// 获取请求的缓存规则
print(requestSwf?.cachePolicy as Any)
// 获取请求体(body)
print(requestSwf?.httpBody as Any)
// 获取请求的方法
print(requestSwf?.httpMethod as Any)
// TODO: 输出请求响应对象
let responseSwf = DDResponse.response
print(responseSwf!)
/**
输出响应对象:
{ URL: http://www.jianshu.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: 输出请求的错误信息
print(DDResponse.error as Any)
// TODO: 获取请求/响应统计信息的任务指标。
print(DDResponse.metrics!)
}
// TODO: 以二进制数据形式输出请求结果(也可以说解析请求结果)
dataRequest.responseData { (data) in
print(data)
/*输出:SUCCESS: 24039 bytes */
}
//TODO: 以JSON形式的输出请求数据(以JOSN形式解析结果)
dataRequest.responseJSON { (dataResponse) in
// 输出一个 'DataResponse' 的对象
print(dataResponse)
// 通过‘DataResponse’ 我们可以获取一些信息
// 1.请求的连接
print(dataResponse.request!)
// 2. 请求响应的对象
print(dataResponse.response!)
// 3. 请求返回的数据
print(dataResponse.data!)
// 4. 服务器返回的结果
print(dataResponse.result)
// 5.完成请求需要的时间
print(dataResponse.timeline)
}
//TODO: 将返回数据以字符串的形式解析
dataRequest.responseString { (dataResponse) in
// 输出一个 'DataResponse' 的对象
print(dataResponse)
// 通过‘DataResponse’ 我们可以获取一些信息
// 1.请求的连接
print(dataResponse.request!)
// 2. 请求响应的对象
print(dataResponse.response!)
// 3. 请求返回的数据
print(dataResponse.data!)
// 4. 服务器返回的结果
print(dataResponse.result)
// 5.完成请求需要的时间
print(dataResponse.timeline)
}
//TODO: 将数据以PLIST文件形式输出
dataRequest.responsePropertyList { (dataResponse) in
// 输出一个 'DataResponse' 的对象
print(dataResponse)
// 通过‘DataResponse’ 我们可以获取一些信息
// 1.请求的连接
print(dataResponse.request!)
// 2. 请求响应的对象
print(dataResponse.response!)
// 3. 请求返回的数据
print(dataResponse.data!)
// 4. 服务器返回的结果
print(dataResponse.result)
// 5.完成请求需要的时间
print(dataResponse.timeline)
}
//TODO: 在线程中处理请求的数据
let dispathQu = DispatchQueue.main
dataRequest.response(queue: dispathQu) { (ddataResponse) in
// 返回一个‘DefaultDataResponse’ 对象
print(ddataResponse)
// 1、获取请求体
print(ddataResponse.request!)
// 2、获取请求响应体
print(ddataResponse.response!)
// 3、获取请求数据
print(ddataResponse.data!)
// 4、获取请求的错误信息
print(ddataResponse.error!)
}
// 请求的进度
print(dataRequest.progress)
}
2、Alamofire的带参数的GET请求
// TODO: Alamofire的GET请求带参数
func alamofireGet2() -> Void {
let dataResponse = Alamofire.request("http://gc.ditu.aliyun.com/geocoding",parameters:["a":"北京"])
// 请求返回的结果
print(dataResponse)
// 对请求的结果处理
dataResponse.responseData { (dataRequ) in
if let data = dataRequ.data {
let strData = String.init(data: data, encoding: String.Encoding.utf8)
print(strData!)
/**
输出的结果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
3、Alamofire的GET请求和返回数据一起处理的写法
// TODO: Alamofire的GET请求和返回数据一起处理的写法
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!)
/**
输出的结果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
Alamofire 的POST请求
// MARK: Alamofire的POST请求
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!)
/**
输出的结果:
{"lon":116.40752,"level":1,"address":"","cityName":"","alevel":4,"lat":39.90403}
*/
}
}
}
POST 和 GET 的友情快递
对于POST 和 GET的区别是:GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 (返回数据)。
Alamofire 可以自定义请求
1、只定义请求方式的请求
// MARk:自定义请求
func customRequestMethod() -> Void {
// 创建请求体
let urlRequest = try! URLRequest.init(url: "http://www.jianshu.com/u/23dd8d9701bf", method: .get)
Alamofire.request(urlRequest).responseString { (dataRequest) in
print(dataRequest.data!)
}
}
method 可选参数如下:
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、可是设置请求的缓存策略和请求超时的时间的请求
// MARK: 可是设置请求的缓存策略和请求超时的时间
func customRequestMethod1() -> Void {
// 创建请求体
let urlRequest = URLRequest.init(url: URL.init(string: "http://www.jianshu.com/u/23dd8d9701bf")!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30)
Alamofire.request(urlRequest).responseData { (dataQuest) in
print(dataQuest.data!)
}
}
@ cachePolicy 是请求缓存策略参数
@ timeoutInterval 是请求超时时间参数
3、可设置请求方式和请求头的请求
// MARK: 可设置请求方式和请求头的请求
func customRequestMethod2() -> Void {
// 创建请求体
let urlRequest = try! URLRequest.init(url: "http://www.jianshu.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 设置请求方式
@ headers 设置请求头
Alamofire 的上传参数编码的请求
Alamofire 的请求参数编码有以下几种:
1、 URLEncoding 是 “URL” 网址编码规则
2、 JSONEncoding 是 “JSON” 格式编码规则
3、 PropertyListEncoding 是 “PLIST” 文件编码规则
使用举例如下:
//MARK: 上传参数使用指定的编码格式上传的请求
func parameterCodingRequest() -> Void {
// 请求的参数
let parameter = ["type":"hot","offset":"0","limit":"10"]
/**
参数的所有编码形式如下,即 “ParameterEncoding” 的扩展对象:
1、 URLEncoding 是 “URL” 网址编码规则
2、 JSONEncoding 是 “JSON” 格式编码规则
3、 PropertyListEncoding 是 “PLIST” 文件编码规则
*/
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() 函数的介绍
1、 validate() 函数是啥?
确认响应有默认可接受的200~299范围内的状态码,还有内容类型匹配在Accept HTTP头字段中指定的任何值。如果验证失败,随后对响应处理程序的调用将会有一个相关的错误。
2、请求信息的验证之 “validate”
// MARK: 请求信息的验证之 “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("获取信息失败!!")
}
}
}
3、验证请求状态码在 “200~299” 之间的请求,否则,不验证。
// MARK: 验证请求状态码在 “200~299” 之间的请求,否则,不验证。
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、验证指定请求媒体信息格式的请求
// MARK: 验证指定请求媒体信息格式的请求
func verifyRequestMediaFormatRequest() -> Void {
/**
友情大爆炸:
1、contentType : 即是 “Internet Media Type” 称之为 互联网媒体类型,也叫 “MIME”。作用是在 "HTTP" 请求头中使用“contentType”来指定不同格式的请求信息。
2、contentType 常见的媒体格式类型如下:
text/html :HTML格式
text/plain :纯文本格式
text/xml :XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png :png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml :XML数据格式
application/atom+xml :Atom XML聚合格式
application/json :JSON数据格式
application/pdf :pdf格式
application/msword :Word文档格式
application/octet-stream :二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded :
5、我们可以根据某个条件,来设定返回的验证结果 “ValidationResult”
// MARK: 我们可以根据某个条件,来设定返回的验证结果 “ValidationResult”
func customizationValidationResult() -> Void {
Alamofire.request("http://m.maoyan.com/cinemas.json").validate { (urlRequest, httpUrlResponse, data) -> Request.ValidationResult in
// 在这里我们可以提前检验 请求的 “URLRequest”、“HTTPURLResponse” 和 返回的数据 “Data” 等来设置请求返回的 “ValidationResult”
if !(urlRequest?.url?.absoluteString.contains("NetWork"))! {
let error = NSError.init(domain: "m.maoyan.com", code: 320, userInfo: ["msg":"请求不包含指定的参数"]) 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": "请求不包含指定的参数"]
*/
}
}
}