74-Swift之Alamofire的基本使用和介绍(GET/POST)

前言

本篇是介绍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!)
        /**
         输出响应对象:
         <NSHTTPURLResponse: 0x608000221020> { 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 :<form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
     */
    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("获取信息失败!!!")
        }
    }
}

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": "请求不包含指定的参数"]
                 */
            }
    }
}

推荐阅读更多精彩内容