• Swift:网络库Alamofire


    一,Alamofire的说明与配置

    1,什么是Alamofire
    (1)Alamofire 的前身是 AFNetworking。AFNetworking 是 iOS 和 OS X 上很受欢迎的第三方HTTP网络基础库。
    (2)其实 AFNetwork 的前缀 AF 便是 Alamofire 的缩写。
    (3)Swift发布后,AFNetworking的作者又用Swift语言写了个相同功能的库,这便是 Alamofire。
    (4)Alamofire 本质是基于`NSURLSession`,并做了封装。使用 Alamofire 可以让我们网络请求相关代码(如获取数据,提交数据,上传文件,下载文件等)更加简洁易用。
    关于Cookie:
    Alamofire是基于NSURLRequest封装的,所以Cookie会自动保存,就和浏览器请求是一个效果。而且网站Set_cookie多久, 本地的Cookie就多久,每次请求的时候都会自动带上cookie,直到过期。(所以像登陆session这些的都不用我们手动去处理)

    2,Alamofire的功能特性:
    (1)链式的请求/响应方法
    (2)URL / JSON / plist参数编码
    (3)上传类型支持:文件(File )、数据(Data )、流(Stream)以及MultipartFormData
    (4)支持文件下载,下载支持断点续传
    (5)支持使用NSURLCredential进行身份验证
    (6)HTTP响应验证
    (7)TLS Certificate and Public Key Pinning
    (8)Progress Closure & NSProgress

    3,Alamofire的安装与配置
    (1)从 GitHub 上下载最新的代码:https://github.com/Alamofire/Alamofire
    (2)将下载下来的源码包中 Alamofire.xcodeproj 拖拽至你的工程中
    原文:Swift - HTTP网络操作库Alamofire使用详解1(配置,以及数据请求)

    (3)工程 -> General -> Embedded Binaries项,把iOS版的framework添加进来: Alamofire.framework
    原文:Swift - HTTP网络操作库Alamofire使用详解1(配置,以及数据请求)
    原文:Swift - HTTP网络操作库Alamofire使用详解1(配置,以及数据请求)

    (4)最后,在需要使用 Alamofire 的地方 import 进来就可以了
    1
    import Alamofire

    二,使用Alamofire进行数据请求

    1,以GET请求为例
    (1)不带参数,不带结果处理
    1
    Alamofire.request(.GET, "https://httpbin.org/get")
    (2)带参数,不带结果处理
    1
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])

    (3)带参数,也带结果处理(这里以返回结果为json格式的为例)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
             .responseJSON { response in
                 print(response.request)  // original URL request
                 print(response.response) // URL response
                 print(response.data)     // server data
                 print(response.result)   // result of response serialization
     
                 if let JSON = response.result.value {
                     print("JSON: (JSON)") //具体如何解析json内容可看下方“响应处理”部分
                 }
             }

    2,响应处理(Response Handling)
    (1)除了上面样例使用的responseJSON(处理json类型的返回结果)外,Alamofire还提供了许多其他类型的响应处理方法:
    response()
    responseData()
    responseString(encoding: NSStringEncoding)
    responseJSON(options: NSJSONReadingOptions)
    responsePropertyList(options: NSPropertyListReadOptions)

    (2)Response Handler
    1
    2
    3
    4
    5
    6
    7
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
             .response { request, response, data, error in
                 print(request)
                 print(response)
                 print(data)
                 print(error)
              }
    (3)Response Data Handler
    1
    2
    3
    4
    5
    6
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
             .responseData { response in
                 print(response.request)
                 print(response.response)
                 print(response.result)
              }
    (4)Response String Handler
    1
    2
    3
    4
    5
    Alamofire.request(.GET, "https://httpbin.org/get")
             .responseString { response in
                 print("Success: (response.result.isSuccess)")
                 print("Response String: (response.result.value)")
             }
    (5)Response JSON Handler
    使用responseJSON 方法的话,JSON数据会被自动转化为 NSDictionary或NSArray。假设我们返回的json数据格式如下:
    [
        {
            "name": "hangge",
            "phones": [
                {
                    "name": "公司",
                    "number": "123456"
                },
                {
                    "name": "家庭",
                    "number": "001"
                }
            ]
        },
        {
            "name": "big boss",
            "phones": [
                {
                    "name": "公司",
                    "number": "111111"
                }
            ]
        }
    ]
    使用responseJSON自动解析son数据:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Alamofire.request(.GET, "http://www.hangge.com/jsonData.php")
        .responseJSON { response in
            switch response.result {
            case .Success:
                //把得到的JSON数据转为数组
                if let items = response.result.value as? NSArray{
                    //遍历数组得到每一个字典模型
                    for dict in items{
                        print(dict)
                    }
                }
            case .Failure(let error):
                print(error)
            }
    }
    (6)同样也支持链式的返回结果处理
    1
    2
    3
    4
    5
    6
    7
    Alamofire.request(.GET, "https://httpbin.org/get")
             .responseString { response in
                 print("Response String: (response.result.value)")
             }
             .responseJSON { response in
                 print("Response JSON: (response.result.value)")
             }
    3,请求类型(HTTP Methods)
    除了上面使用的 .Get 类型。Alamofire还定义了许多其他的HTTP 方法(HTTP Medthods)可以使用。
    1
    2
    3
    public enum Method: String {
        case OPTIONS, GET, HEAD, POST, PUT, PATCH, DELETE, TRACE, CONNECT
    }
    比如要使用 POST 请求,把 Alamofire.request 第一个参数做修改即可:
    1
    Alamofire.request(.POST, "http://httpbin.org/post")

    4,请求参数(Parameters)
    (1)使用GET类型请求的时候,参数会自动拼接在url后面
    1
    2
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
    (2)使用POST类型请求的时候,参数是放在在HTTP body里传递,url上看不到
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    let parameters = [
        "foo": "bar",
        "baz": ["a", 1],
        "qux": [
            "x": 1,
            "y": 2,
            "z": 3
        ]
    ]
     
    Alamofire.request(.POST, "https://httpbin.org/post", parameters: parameters)
    // HTTP body: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3

    5,参数编码方式(Parameter Encoding)
    除了默认的方式外,Alamofire还支持URL、URLEncodedInURL、JSON、Property List以及自定义格式方式编码参数。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    enum ParameterEncoding {
        case URL
        case URLEncodedInURL
        case JSON
        case PropertyList(format: NSPropertyListFormat, options: NSPropertyListWriteOptions)
        case Custom((URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?))
     
        func encode(request: NSURLRequest, parameters: [String: AnyObject]?) -> (NSURLRequest, NSError?)
        { ... }
    }
    比如我们想要把一个字典类型的数据,使用json格式发起POST请求:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let parameters = [
        "foo": [1,2,3],
        "bar": [
            "baz": "qux"
        ]
    ]
     
    Alamofire.request(.POST, "https://httpbin.org/post", parameters: parameters, encoding: .JSON)
    // HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}}
    服务端php页面可以这么取得发送过来的JSON数据:
    1
    2
    3
    4
    5
    6
    7
    8
    <?
    $postdata = json_decode(file_get_contents("php://input"),TRUE);
     
    $foo= $postdata["foo"];
    foreach ($foo as $item){
      echo $item."|";
    }
    //输出:1|2|3|

    6,支持自定义Http头信息(HTTP Headers)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let headers = [
        "Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
        "Content-Type": "application/x-www-form-urlencoded"
    ]
     
    Alamofire.request(.GET, "https://httpbin.org/get", headers: headers)
             .responseJSON { response in
                 debugPrint(response)
             }

    三,判断数据请求是否成功,并做相应的处理
    在请求响应对象之前调用的 .validate() 函数是另一个易用的 Alamofire 特性。
    将其与请求和响应链接,以确认响应的状态码在默认可接受的范围(200到299)内。如果认证失败,响应处理方法将出现一个相关错误,我们可以根据不同在完成处理方法中处理这个错误。
    比如下面的样例,成功时会打印成功信息,失败时输出具体错误信息。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
        .validate()
        .responseJSON { response in
            switch response.result {
            case .Success:
                print("数据获取成功!")
            case .Failure(let error):
                print(error)
            }
    }

    四,打印调试(print和debugPrint)
    不管是 request对象还是 response对象都是支持打印输出的。根据不同的调试需求,我们可以自行选择使用 print 还是 debugPrint。
    1,打印request对象
    1
    2
    3
    4
    5
    6
    let request = Alamofire.request(.GET, "https://httpbin.org/ip", parameters: ["foo": "bar"])
    print(request)
     
    /********** 下面是控制台输出 ***************
    ******************************************/
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let request = Alamofire.request(.GET, "https://httpbin.org/ip", parameters: ["foo": "bar"])
    debugPrint(request)
     
    /********** 下面是控制台输出 ***************
    $ curl -i
        -H "User-Agent: hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))"
        -H "Accept-Encoding: gzip;q=1.0,compress;q=0.5"
        -H "Accept-Language: zh-Hans-CN;q=1.0,en-CN;q=0.9"
    ******************************************/

    2,打印response对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Alamofire.request(.GET, "https://httpbin.org/get")
        .responseString { response in
        debugPrint(response)
    }
     
    /********** 下面是控制台输出 ***************
    SUCCESS: {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip;q=1.0,compress;q=0.5",
        "Accept-Language": "zh-Hans-CN;q=1.0,en-CN;q=0.9",
        "Host": "httpbin.org",
        "User-Agent": "hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))"
      },
      "origin": "180.109.163.139",
    }
    ******************************************/
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    Alamofire.request(.GET, "https://httpbin.org/get")
        .responseString { response in
        print(response)
    }
     
    /********** 下面是控制台输出 ***************
    [Request]: <NSMutableURLRequest: 0x7889c780> { URL: https://httpbin.org/get }
    [Response]: <NSHTTPURLResponse: 0x7896f500> { URL: https://httpbin.org/get } { status code: 200, headers {
        "Access-Control-Allow-Origin" = "*";
        "Content-Length" = 354;
        "Content-Type" = "application/json";
        Date = "Tue, 08 Dec 2015 01:57:45 GMT";
        Server = nginx;
        "access-control-allow-credentials" = true;
    } }
    [Data]: 354 bytes
    [Result]: SUCCESS: {
      "args": {},
      "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip;q=1.0,compress;q=0.5",
        "Accept-Language": "zh-Hans-CN;q=1.0,en-CN;q=0.9",
        "Host": "httpbin.org",
        "User-Agent": "hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))"
      },
      "origin": "180.109.163.139",
    }
     
    ******************************************/
    六,使用Alamofire进行文件上传

    1,Alamofire支持如下上传类型:
    File
    Data
    Stream
    MultipartFormData

    2,使用文件流的形式上传文件
    1
    2
    3
    let fileURL = NSBundle.mainBundle().URLForResource("hangge", withExtension: "zip")
     
    Alamofire.upload(.POST, "http://www.hangge.com/upload.php", file: fileURL!)
      附:服务端代码(upload.php)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?php 
    /** php 接收流文件
    * @param  String  $file 接收后保存的文件名
    * @return boolean
    */ 
    function receiveStreamFile($receiveFile){   
        $streamData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : ''
       
        if(empty($streamData)){ 
            $streamData = file_get_contents('php://input'); 
        
       
        if($streamData!=''){ 
            $ret = file_put_contents($receiveFile, $streamData, true); 
        }else
            $ret = false; 
        
      
        return $ret;   
     
    //定义服务器存储路径和文件名
    $receiveFile $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/hangge.zip"
    $ret = receiveStreamFile($receiveFile); 
    echo json_encode(array('success'=>(bool)$ret)); 
    ?>

    3,上传时附带上传进度
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    let fileURL = NSBundle.mainBundle().URLForResource("hangge", withExtension: "zip")
     
    Alamofire.upload(.POST, "http://www.hangge.com/upload.php", file: fileURL!)
             .progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
                 print(totalBytesWritten)
     
                 // This closure is NOT called on the main queue for performance
                 // reasons. To update your ui, dispatch to the main queue.
                 dispatch_async(dispatch_get_main_queue()) {
                     print("Total bytes written on main queue: (totalBytesWritten)")
                 }
             }
             .responseJSON { response in
                 debugPrint(response)
             }
    可以看到控制台不断输出已上传的数据大小: 
    原文:Swift - HTTP网络操作库Alamofire使用详解2(文件上传)

    4,上传MultipartFormData类型的文件数据(类似于网页上Form表单里的文件提交)
    (1)上传两个文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    let fileURL1 = NSBundle.mainBundle().URLForResource("hangge", withExtension: "png")
    let fileURL2 = NSBundle.mainBundle().URLForResource("hangge", withExtension: "zip")
             
    Alamofire.upload(
        .POST,
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(fileURL: fileURL1!, name: "file1")
            multipartFormData.appendBodyPart(fileURL: fileURL2!, name: "file2")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseJSON { response in
                    debugPrint(response)
                }
            case .Failure(let encodingError):
                print(encodingError)
            }
        }
    )
      附:服务端代码(upload2.php)
    1
    2
    3
    4
    5
    6
    7
    <? 
    move_uploaded_file($_FILES["file1"]["tmp_name"],
        $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/" . $_FILES["file1"]["name"]);
     
    move_uploaded_file($_FILES["file2"]["tmp_name"],
        $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/" . $_FILES["file2"]["name"]);
    ?>

    (2)文本参数与文件一起提交(文件除了可以使用fileURL,还可以上传NSData类型的文件数据)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    //字符串
    let strData = "hangge.com".dataUsingEncoding(NSUTF8StringEncoding)
    //数字
    let intData = String(10).dataUsingEncoding(NSUTF8StringEncoding)
    //文件1
    let path = NSBundle.mainBundle().pathForResource("hangge", ofType: "png")!
    let file1Data = NSData(contentsOfFile: path)
    //文件2
    let file2URL = NSBundle.mainBundle().URLForResource("hangge", withExtension: "zip")
     
    Alamofire.upload(
        .POST,
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(data: strData!, name: "value1")
            multipartFormData.appendBodyPart(data: intData!, name: "value2")
            multipartFormData.appendBodyPart(data: file1Data!, name: "file1",
                fileName: "h.png", mimeType: "image/png")
            multipartFormData.appendBodyPart(fileURL: file2URL!, name: "file2")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {
            case .Success(let upload, _, _):
                upload.responseString { response in
                    print(response)
                }
            case .Failure(let encodingError):
                print(encodingError)
            }
        }
    )
      附:服务端代码(upload2.php)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?
    $value1 = $_POST["value1"];
    $value2 = $_POST["value2"];
     
    move_uploaded_file($_FILES["file1"]["tmp_name"],
        $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/" . $_FILES["file1"]["name"]);
      
    move_uploaded_file($_FILES["file2"]["tmp_name"],
        $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/" . $_FILES["file2"]["name"]);
    ?>
    七,使用Alamofire进行文件下载

    1,自定义下载文件的保存目录
    下面代码将logo图片下载下来保存到用户文档目录下(Documnets目录),文件名不变。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Alamofire.download(.GET, "http://www.hangge.com/blog/images/logo.png") {
        temporaryURL, response in
        let fileManager = NSFileManager.defaultManager()
        let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory,
            inDomains: .UserDomainMask)[0]
        let pathComponent = response.suggestedFilename
                 
        return directoryURL.URLByAppendingPathComponent(pathComponent!)
    }
    将logo图片下载下来保存到用户文档目录下的file1子目录(Documnets/file1目录),文件名改成myLogo.png。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Alamofire.download(.GET, "http://www.hangge.com/blog/images/logo.png") {
        temporaryURL, response in
        let fileManager = NSFileManager.defaultManager()
        let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory,
            inDomains: .UserDomainMask)[0]
         
        let folder = directoryURL.URLByAppendingPathComponent("file1", isDirectory: true)
        //判断文件夹是否存在,不存在则创建
        let exist = fileManager.fileExistsAtPath(folder.path!)
        if !exist {
            try! fileManager.createDirectoryAtURL(folder, withIntermediateDirectories: true,
                attributes: nil)
        }
        return folder.URLByAppendingPathComponent("myLogo.png")
    }

    2,使用默认提供的下载路径
    Alamofire内置的许多常用的下载路径方便我们使用,简化代码。比如,下载到用户文档目录下可以改成:
    1
    2
    3
    4
    5
    let destination = Alamofire.Request.suggestedDownloadDestination(
        directory: .DocumentDirectory, domain: .UserDomainMask)
             
    Alamofire.download(.GET, "http://www.hangge.com/blog/images/logo.png",
        destination: destination)

    3,下载进度
    下面代码在文件下载过程中会不断地打印下载进度,同时下载完成后也会打印完成信息。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let destination = Alamofire.Request.suggestedDownloadDestination(
        directory: .DocumentDirectory, domain: .UserDomainMask)
             
    Alamofire.download(.GET, "http://www.hangge.com/favicon.ico", destination: destination)
        .progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead) in
            let percent = totalBytesRead*100/totalBytesExpectedToRead
            print("已下载:(totalBytesRead)  当前进度:(percent)%")
        }
        .response { (request, response, _, error) in
            print(response)
    }

    4,断点续传(Resume Data) 
    当下载过程中被意外停止时,可以在响应方法中把已下载的部分保存起来,下次再从断点继续下载。
    下面通过样例演示如何断点续传:
    (1)程序启动后自动开始下载文件
    (2)点击“停止下载”,终止下载并把已下载的数据保存起来,进度条停止走动。
    (3)点击“继续下载”,从上次终止的地方继续下载,进度条继续走动。
    原文:Swift - HTTP网络操作库Alamofire使用详解3(文件下载,断点续传)   原文:Swift - HTTP网络操作库Alamofire使用详解3(文件下载,断点续传)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    import UIKit
    import Alamofire
     
    class ViewController: UIViewController {
         
        //停止下载按钮
        @IBOutlet weak var stopBtn: UIButton!
        //继续下载按钮
        @IBOutlet weak var continueBtn: UIButton!
        //下载进度条
        @IBOutlet weak var progress: UIProgressView!
         
        //下载文件的保存路径
        let destination = Alamofire.Request.suggestedDownloadDestination(
            directory: .DocumentDirectory, domain: .UserDomainMask)
         
        //用于停止下载时,保存已下载的部分
        var cancelledData: NSData?
         
        //下载请求对象
        var downloadRequest: Request!
         
        override func viewDidLoad() {
            super.viewDidLoad()
            
            //页面加载完毕就自动开始下载
            self.downloadRequest =  Alamofire.download(.GET,
                destination: destination)
             
            self.downloadRequest.progress(downloadProgress) //下载进度
             
            self.downloadRequest.response(completionHandler: downloadResponse) //下载停止响应
        }
         
        //下载过程中改变进度条
        func downloadProgress(bytesRead: Int64, totalBytesRead: Int64,
            totalBytesExpectedToRead: Int64) {
            let percent = Float(totalBytesRead)/Float(totalBytesExpectedToRead)
             
            //进度条更新
            dispatch_async(dispatch_get_main_queue(), {
                self.progress.setProgress(percent,animated:true)  
            })
            print("当前进度:(percent*100)%")
        }
         
        //下载停止响应(不管成功或者失败)
        func downloadResponse(request: NSURLRequest?, response: NSHTTPURLResponse?,
            data: NSData?, error:NSError?) {
            if let error = error {
                if error.code == NSURLErrorCancelled {
                    self.cancelledData = data //意外终止的话,把已下载的数据储存起来
                } else {
                    print("Failed to download file: (response) (error)")
                }
            } else {
                print("Successfully downloaded file: (response)")
            }
        }
         
        //停止按钮点击
        @IBAction func stopBtnClick(sender: AnyObject) {
            self.downloadRequest?.cancel()
            self.stopBtn.enabled = false
            self.continueBtn.enabled = true
        }
         
        //继续按钮点击
        @IBAction func continueBtnClick(sender: AnyObject) {
            if let cancelledData = self.cancelledData {
                self.downloadRequest = Alamofire.download(resumeData: cancelledData,
                    destination: destination)
                 
                self.downloadRequest.progress(downloadProgress) //下载进度
                 
                self.downloadRequest.response(completionHandler: downloadResponse) //下载停止响应
                 
                self.stopBtn.enabled = true
                self.continueBtn.enabled = false
            }
        }
     
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
        }
    }
    八,使用Alamofire进行用户认证

    1,Alamofire支持如下几种认证(Authentication)
    HTTP Basic
    HTTP Digest
    Kerberos
    NTLM
    本文讲解使用 Alamofire 进行 HTTP Basic 验证。

    2,HTTP Basic认证介绍
    (1)HTTP Basic认证是允许HTTP服务器对WEB浏览器进行用户身份证的方法。 
    (2)当一个客户端向HTTP服务器进行数据请求时,客户端会接收到HTTP服务器的身份认证要求,这时客户端会提示用户输入用户名及密码,然后将用户名及密码以BASE64加密。并于每次请求数据时,将密文附加于请求头(Request Header)中。
    (3)HTTP服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64加密的用户名和密码),解开请求包,对用户名及密码进行验证, 如果用户名及密码正确,则根据客户端请求,返回客户端所需要的数据。否则,返回错误代码或重新要求客户端提供用户名及密码。

    3,HTTP Basic认证的使用场景
    HTTP基本认证只提供简单的用户验证功能,优点是使用简单,适合于对安全性要求不高的系统或设备中。
    比如:路由器的配置页面就常使用HTTP Basic认证。(浏览器输入路由器ip地址,如192.168.1.1,这时就会弹出个用户密码输入框进行权限验证。)

    4,HTTP Basic认证的缺点
    (1)没有灵活可靠的认证策略,如无法提供域(domain或realm)认证功能。
    (2)BASE64 的加密强度非常低。当然,HTTP基本认证系统也可以与SSL或者Kerberos结合,实现安全性能较高(相对)的认证系统。

    5,服务端代码
    为了测试Alamofire的认证功能,我们首先要在服务端创建个带有认证的页面用于测试。这里以PHP为例:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?php
    //HTTP Basic认证
    function authenticate()  
        header('WWW-Authenticate: Basic realm=""'); 
        header('HTTP/1.0 401 Unauthorized'); 
        echo "请输入正确的用户名和密码"
        exit
    }
     
    if (!isset($_SERVER['PHP_AUTH_USER']) ||
        addslashes($_SERVER['PHP_AUTH_USER'])!= 'hangge' ||
        addslashes($_SERVER['PHP_AUTH_PW'])!= '123')  
        //认证失败
        authenticate();
    else 
        //认证成功
        echo "欢迎您: {$_SERVER['PHP_AUTH_USER']}<br />"
        echo "当前时间:".date('h:i:s'); 
         
        //authenticate(); //重新开始 
    ?>
    使用浏览器访问这个authenticate.php页面,则会弹出对话框要求输入用户名和密码:
    原文:Swift - HTTP网络操作库Alamofire使用详解4(用户权限认证)


    如果输入正确的用户名(hangge)和密码(123)则返回正常的数据,否则返回错误信息并需要继续输入:
       原文:Swift - HTTP网络操作库Alamofire使用详解4(用户权限认证) 原文:Swift - HTTP网络操作库Alamofire使用详解4(用户权限认证)

    6,客户端代码
    使用Alamofire进行认证:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let user = "hangge"
    let password = "123"
             
    Alamofire.request(.GET, "http://www.hangge.com/authenticate.php")
        .authenticate(user: user, password: password)
        .responseString  { response in
           // debugPrint(response)
            print(response.result.value)
    }
    从控制台打印的消息可以看出,认证通过,并成功获取到数据:
    原文:Swift - HTTP网络操作库Alamofire使用详解4(用户权限认证)




  • 相关阅读:
    js 每个月有多少天算法
    js 树的操作
    画线
    程序员如何防止脑疲劳
    汉字求出拼音缩写
    datagird 多行外于编辑状态
    overflow: hidden 失效
    CSS 相对/绝对(relative/absolute)定位系列(三)
    display:inlineblock在Chrome与FF下导致的间隙
    css ul li 的使用及浏览器兼容问题
  • 原文地址:https://www.cnblogs.com/shaoting/p/5463129.html
Copyright © 2020-2023  润新知