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" ,
   "url" : "https://httpbin.org/get"
}
******************************************/
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" ,
   "url" : "https://httpbin.org/get"
}
 
******************************************/
六,使用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(用戶權限認證)





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM