iOS - Alamofire 網絡請求


前言

  • Alamofire 是 Swift 語言的 HTTP 網絡開發工具包,相當於 Swift 實現 AFNetworking 版本。當然,AFNetworking 非常穩定,在 Mac OSX 與 iOS 中也能像其他 Objective-C 代碼一樣用 Swift 編寫。不過 Alamofire 更適合 Swift 語言風格習慣(Alamofire 與 AFNetworking 可以共存一個項目中,互不影響)。Alamofire 取名來源於 Alamo Fire flower。

  • Alamofire 的核心主要是試圖簡化 iOS 中 HTTP 網絡連接,它通過使用 NSURLSession 以及 Foundation URL Loading System 來創建一個 Swift 本地的網絡訪問接口,從而實現令人難以置信效率的任務。

1、Alamofire

  • Alamofire 功能:

    • Chainable Request / Response methods
    • URL / JSON / plist Parameter Encoding
    • Upload File / Data / Stream
    • Download using Request or Resume data
    • Authentication with NSURLCredential
    • Progress Closure & NSProgress
    • cURL Debug Output
  • Alamofire 系統需求:

    Alamofire Version     |    Minimum iOS Target    |          Target Notes
    

    ------------------------|--------------------------|-------------------------------------------------------------------
    3.4.x | iOS 8.0+ | Xcode 7.3+ is required.
    3.1.4 -> 3.3.1 | iOS 8.0+ | Xcode 7.2+ is required.
    3.1.0 -> 3.1.3 | iOS 8.0+ | Xcode 7.1+ is required.
    2.0.0 -> 3.0.1 | iOS 8.0+ | Xcode 7.0+ is required.
    1.3.0 -> 1.3.1 | iOS 7.0+ | Xcode 6.4 is required.
    1.2.1 -> 1.2.3 | iOS 7.0+ | Xcode 6.3 is required.
    1.1.0 -> 1.2.0 | iOS 7.0+ | Xcode 6.1 is required.
    1.0.0 -> 1.0.1 | iOS 7.0+ | Xcode 6.0 is required. For Xcode 6.1, use the xcode-6.1 branch.

  • Alamofire 有許多讓程序猿信服去使用它的理由。在 iOS 開發中,使用 NURLSession 是 HTTP 網絡的未來趨勢, 相比 NSURLConnection 來說,它的功能更加豐富:

    • 后台上傳和下載
    • 暫停以及重新開始網絡操作的能力
    • 可配置的容器(Container)
    • 子類和私有存儲
    • 改進的認證處理
    • 對每個基礎連接進行身份驗證
    • 多種代理模式 -- NSURLConnection 擁有異步代碼塊的基本方法, 但是不能用它們的代理,NSURLSession 具有一種混合型的方法。
  • 對 AFNetworking 能做而 Alamofire 不能做的有以下幾點:

    • UIKit 擴展
    • TLS 驗證
    • NSOperation/NSURLConnection/AFURLConnectionOperation 調用
    • 多重 HTTP 網絡請求構架

2、Alamofire 的添加

  • Github 網址:https://github.com/Alamofire/Alamofire

  • Alamofire 使用 ARC

  • Swift

    	// 將第三方庫文件復制到工程目錄下
    	Alamofire		
    	
    	// 將第三方庫文件中的 xcodeproj 添加到工程中
    	Alamofire.xcodeproj
        
    	// 在 TARGETS -> General -> Embedded Binaries 下添加靜態庫文件(添加上邊的)
    	Alamofire.framework
        
    	// 添加頭文件
    	import Alamofire
    

3、Alamofire 的設置

  • Swift

    • 請求超時時間設置

      	// 必須設置為全局的
      	var alamofireManager: Manager!
      	
      	let config = NSURLSessionConfiguration.defaultSessionConfiguration()
      	config.timeoutIntervalForRequest = 5     // 秒
        	
      	self.alamofireManager = Manager(configuration: config)
      	self.alamofireManager.request(.GET, "http://120.25.226.186:32812/video?type=JSON")
      
    • HTTP 方法(Medthods)

      	Alamofire.Method enum 列表出在 RFC 2616 中定義的 HTTP 方法:
      
      		public enum Method: 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"
      		}
      
      	這些值可以作為 Alamofire.request 請求的第一個參數。
              
      	Alamofire.request(.POST, "https://httpbin.org/post")
          
      	Alamofire.request(.PUT, "https://httpbin.org/put")
          
      	Alamofire.request(.DELETE, "https://httpbin.org/delete")
      
    • 請求參數編碼方式設置

          Alamofire 使用 Alamofire.ParameterEncoding 可以支持 URL query/URI form,JSON,PropertyList 方式編碼參數。
      
          enum ParameterEncoding {
              
              case URL
              case URLEncodedInURL
              case JSON
              case PropertyList(NSPropertyListFormat, NSPropertyListWriteOptions)
              case Custom((URLRequestConvertible, [String : AnyObject]?) -> (NSMutableURLRequest, NSError?))
              
              public func encode(URLRequest: URLRequestConvertible, parameters: [String : AnyObject]?) -> (NSMutableURLRequest, NSError?)
              public func queryComponents(key: String, _ value: AnyObject) -> [(String, String)]
              public func escape(string: String) -> String
          }
       	
          // URL 形式參數編碼
          
           	// 發送以下 HttpBody 內容: foo=bar&baz[]=a&baz[]=1&qux[x]=1&qux[y]=2&qux[z]=3
          
          	let urlStr:URLStringConvertible = "https://httpbin.org/post"
          	let parameters:[String: AnyObject]? = ["foo":"bar", "baz":["a", 1], "qux":["x":1, "y":2, "z":3]]
          
              Alamofire.request(.POST, urlStr, parameters: parameters)        // 默認編碼方式是 URL
          
      		Alamofire.request(.POST, urlStr, parameters: parameters, encoding: .URL)
      
          // JSON 形式參數編碼
          
           	// 發送以下 HttpBody 內容: {"foo":"bar", "baz":["a", 1], "qux":{"x":1, "y":2, "z":3}}
          
          	let urlStr:URLStringConvertible = "https://httpbin.org/post"
          	let parameters:[String: AnyObject]? = ["foo":"bar", "baz":["a", 1], "qux":["x":1, "y":2, "z":3]]
          
              Alamofire.request(.POST, urlStr, parameters: parameters, encoding:.JSON)                		
      
          // URLRequest 請求編碼
      
              let url = NSURL(string: "https://httpbin.org/get")!
              var urlRequest = NSMutableURLRequest(URL: url)
                  
              let param = ["foo": "bar"]
              let encoding = Alamofire.ParameterEncoding.URL
          
              (urlRequest, _) = encoding.encode(urlRequest, parameters: param)
      
    • 請求頭設置

      	let headers = ["User-Agent":"iPhone 6s Plus"]
          
      	Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON", headers: headers)
        	
       	// 不設置時為默認值
      	Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
    • 請求數據響應格式設置

      	Built-in Response Methods:
      
      		response()
      		responseData()
      		responseString(encoding:NSStringEncoding)
      		responseJSON(options:NSJSONReadingOptions)
      		responsePropertyList(options:NSPropertyListReadOptions)
      
      	可以同時響應多種格式數據。
      
      	// 響應 NSData 格式數據
          	
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
      			.response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
              
      				/*
      					網絡請求結束,成功時 error == nil。請求返回的數據存在 responseData 中,為 NSData 格式。
      				*/	
      			}
          
      	// 響應 String 格式數據
          		
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
      			.responseString { (response:Response<String, NSError>) in
                  
      				/*
      						網絡請求結束,成功時 response.result.error == nil。請求返回的數據存在 response.result.value 中,為 String 格式。
                    		或者成功時 response.result 的值為 .Success,失敗時 response.result 的值為 .Failure。
      				*/	
      
      				response.request     // original URL request
      				response.response    // URL response
      				response.data        // server data
      				response.result      // result of response serialization
      
      				// 獲取並判斷結果值
      
      				if let string = response.result.value {
                          	
      				} else {
                          	
      				}
                      
      				// 判斷結果值
      
      				if response.result.error == nil {
      
      				} else {
      
      				}
                      
      				// 判斷結果值
      
      				switch response.result {
                          
      					case.Success(let value):
      					case.Failure(let error):
      				}
      			}
          
      	// 響應 JSON 格式數據
          	
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
      			.responseJSON { (response:Response<AnyObject, NSError>) in
                  
      				/*
      					網絡請求結束,成功時 response.result.error == nil。請求返回的數據存在 response.result.value 中,為 JSON 格式。
      					或者成功時 response.result 的值為 .Success,失敗時 response.result 的值為 .Failure。
      				*/	
      			}
          
      	// 響應 PList 格式數據
          	
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
      			.responsePropertyList { (response:Response<AnyObject, NSError>) in
      
      				/*
                  		網絡請求結束,成功時 response.result.error == nil。請求返回的數據存在 response.result.value 中,為 PList 格式。
      					或者成功時 response.result 的值為 .Success,失敗時 response.result 的值為 .Failure。
      				*/	
      			}
      
      	// 響應 多種格式 數據
      
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
               	// 參數不使用時可以省略
      			.response { (_, _, responseData:NSData?, error:NSError?) in
      
      			}
      
      			.responseJSON { (response:Response<AnyObject, NSError>) in
      
      			}
      
    • Request 請求創建方式

      	// Manager 方式
          
          	// 必須設置為全局的
      		var alamofireManager: Manager!
      
      		self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
          
      		self.alamofireManager.request(.GET, "http://120.25.226.186:32812/video?type=JSON")
          
      	// Alamofire 方式,接收返回值
          
      		let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
          
      	// 不接收返回值,request 不帶參數
      
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
      	// request 帶參數
      
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"])
      	
      	// request 帶參數及參數編碼方式
      
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"], encoding: .URL)
              	
      	// request 帶參數及請求頭
              
      		Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"], 
      		                                                                       encoding: .URL, 
      		                                                                        headers: ["User-Agent":"iPhone 6s"])
      
    • 請求任務創建方式

      	// 數據請求 request (GET/POST)
          
      		// Alamofire GET 方式
              
      			let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
                  
      			Alamofire.request(.GET, urlStr)
          
      		// Alamofire POST 方式
              
      			let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
              
      			Alamofire.request(.GET, urlStr, parameters: ["type": "XML"])
              
      		// Manager GET 方式
              
              	// 必須設置為全局的
      			var alamofireManager: Manager!
      
      			let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
                  
      			self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
                  
      			self.alamofireManager.request(.GET, urlStr)
          
      		// Manager POST 方式
              
              	// 必須設置為全局的
      			var alamofireManager: Manager!
      
      			let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
              
      			self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
              
      			self.alamofireManager.request(.GET, urlStr, parameters: ["type": "XML"])
          
      	// 文件下載 download
          	
      		// 指定文件路徑方式
          	
              	Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
              	          { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
                      
              		/*
              				設置文件下載路徑,temporaryURL 是沙盒下的文件臨時存儲路徑,下載完成后會被自動刪除。response.suggestedFilename 
              			為服務器端文件名。此 block 在子線程中執行。
              		*/
                      
              		return documentsDirUrl
              	}
                      
              		.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
                          
              			/*
              				監聽文件下載進度,此 block 在子線程中執行。
              			*/
              		}
                      
              		.response { (_, _, _, error:NSError?) in
                          
              			/*
              				網絡請求結束,成功時 error == nil。在 Swift 中文件已經存在時,再次相同路徑寫入會失敗。
              			*/
              		}
          
      		// 使用默認提供的下載路徑方式
          
              	Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4", destination: destination)
                      
              		.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
                          
              			/*
              				監聽文件下載進度,此 block 在子線程中執行。
              			*/
              		}
                      
              		.response { (_, _, _, error:NSError?) in
                          
              			/*
              				網絡請求結束,成功時 error == nil。在 Swift 中文件已經存在時,再次相同路徑寫入會失敗。
              			*/
              		}
          
      		// 斷點續傳下載方式
          	
      			let downloadRequest:Request = Alamofire.download(resumeData: resumeData, 
              	                                                destination: { (temporaryURL:NSURL, 
              	                                                                    response:NSHTTPURLResponse) -> NSURL in
                      
      				/*
      						設置文件下載路徑,temporaryURL 是沙盒下的文件臨時存儲路徑,下載完成后會被自動刪除。response.suggestedFilename 
      					為服務器端文件名。此 block 在子線程中執行。
      				*/
                          
      				return documentsDirUrl
      			})
                      
      				.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
                          
      					/*
      						監聽文件下載進度,此 block 在子線程中執行。
      					*/
      				}
                      
      				.response { (_, _, data:NSData?, error:NSError?) in
                          
      					/*
      						網絡請求結束,成功時 error == nil。在 Swift 中文件已經存在時,再次相同路徑寫入會失敗。
      					*/
      				}
          	
      	// 文件上傳 upload
          
      		// Data 形式上傳
          	
      			Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", headers: headers, data: formBody)
                      
      				.progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
                          
      					/*
      						監聽文件上傳進度,此 block 在子線程中執行。
      					*/
      				}
                      
      				.response { (_, _, responseData:NSData?, error:NSError?) in
                          
      					/*
      						網絡請求結束。
      					*/
      				}
          
      		// MultipartFormData 形式上傳
          
      			Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", 
      			                         multipartFormData: { (formData:MultipartFormData) in
                      
      				/*
      					添加參數。第一個參數是需要添加的參數內容值,第二個是后台規定的參數名。
      					設置上傳的文件。第一個參數是需要上傳的文件路徑,第二個是后台規定的參數名,第三個是上傳后服務器端文件名稱,第四個是文件類型。
      				*/
                      
      			}) { (encodingResult:Manager.MultipartFormDataEncodingResult) in
                      
      				/*
      					數據編碼完成。
      				*/
                      
      				switch encodingResult {
                    
                    	// 編碼成功
                     	case .Success(let uploadRequest, _, _):                                                                 
                          
                         	uploadRequest
                              
                           	.progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
                              
                              	/*
                              		監聽文件上傳進度,此 block 在子線程中執行。
                              	*/
                           	}
                              
                           	.response { (_, _, responseData:NSData?, error:NSError?) in
                                  
                              	/*
                              		網絡請求結束。
                              	*/
                           	}
                              
                     	// 編碼失敗
                     	case .Failure(let error):                                                                               
                          
                     		print(error)
      				}
      			}
      
    • 請求任務設置

      	// 繼續請求任務
      	downloadRequest.resume()
          
      	// 暫停請求任務
       	downloadRequest.suspend()
          
      	// 取消請求任務
       	downloadRequest.cancel()
      
    • 文件下載設置

      	// 設置文件下載路徑
      
          	let documentsDirUrl:NSURL = NSFileManager.defaultManager()
          	                                         .URLsForDirectory( .DocumentDirectory, inDomains: .UserDomainMask)[0]
          	                                         .URLByAppendingPathComponent(response.suggestedFilename!)
      
          	if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
              
              	// 移除已經存在的文件,在 Swift 中文件已經存在時,再次相同路徑寫入會失敗
              	try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
          	}
      
      	// 設置文件默認下載路徑
      
          	let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
      
      	// 監聽文件下載進度
      
      		bytesWrite                  // 本次寫入的大小
      		totalBytesWrite             // 已經寫入的大小
        		totalBytesExpectedToWrite   // 總大小
          
          	// 設置下載進度條
          	let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
          	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
      
    • 文件上傳設置

      	// Data 形式上傳
      
          	let boundary = "myBoundary"
          
          	// 設置請求頭
      		/*
          		upload task 不會在請求頭里添加 content-type (上傳數據類型)字段,@"myBoundary" 為請求體邊界,參數可以隨便設置,但需一致
          	*/
          	let headers = ["Content-Type":"multipart/form-data; charset=utf-8; boundary=\(boundary)"]
      
          	// 設置請求文件參數
          
              	let formBody = NSMutableData()
              
              	// 參數開始分割線
              	/*
              		每個參數開始前都需要加
          		*/
              	formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// 參數
              	formBody.appendData("Content-Disposition: form-data; name=\"\("username")\"\r\n\r\n\("jhq")"
              	        .dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// username 是后台規定的參數名,jhq 是需要添加的參數內容值
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// 文件開始分割線
              	/*
              		每個文件開始前都需要加
              	*/
              	formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// 文件參數名
              	formBody.appendData("Content-Disposition: form-data; name=\"\("file")\"; filename=\"\("test.mp4")\""
              	        .dataUsingEncoding(NSUTF8StringEncoding)!)
              	        
              	// file 是后台規定的參數名,test.mp4 為上傳后服務器端文件名稱
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)                    		
              
              	// 文件的類型
              	formBody.appendData("Content-Type: mp4".dataUsingEncoding(NSUTF8StringEncoding)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// 待上傳文件數據
              	/*
              		本地待上傳的文件路徑
              	*/
              	formBody.appendData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
              
              	// 結束分割線標記
              	formBody.appendData("--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)
              	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      	
      	// 指定文件路徑形式上傳
      	/*
      		public func appendBodyPart(fileURL fileURL: NSURL, name: String, fileName: String, mimeType: String);
       
      		第一個參數是需要上傳的文件路徑,第二個是后台規定的參數名,第三個是上傳后服務器端文件名稱,第四個是文件類型。
      	*/
      	let fileUrl = NSBundle.mainBundle().URLForResource("HQ_0005", withExtension: "jpg")!
      	formData.appendBodyPart(fileURL: fileUrl, name: "file", fileName: "test.png", mimeType: "image/jpeg")
          
      	// 指定文件數據形式上傳
      	/*
      		public func appendBodyPart(data data: NSData, name: String, fileName: String, mimeType: String);
               
      		第一個參數是需要上傳的文件數據,第二個是后台規定的參數名,第三個是上傳后服務器端文件名稱,第四個是文件類型。
      	*/
      	let fileData = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)
      	formData.appendBodyPart(data: fileData!, name: "file", fileName: "test.mp4", mimeType: "mp4")
      
      	// 添加參數
      	/*
      		public func appendBodyPart(data data: NSData, name: String);
               
      		第一個參數是需要添加的參數內容值,第二個是后台規定的參數名。
      	*/
      	formData.appendBodyPart(data: "jhq".dataUsingEncoding(NSUTF8StringEncoding)!, name: "username")
              
      	// 監聽文件上傳進度
      
      	bytesLoad                   // 本次寫入的大小
      	totalBytesLoad              // 已經寫入的大小
      	totalBytesExpectedToLoad    // 總大小
          
      	let progressNum1:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
      	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum1, waitUntilDone: true)
      

4、Alamofire HTTP 認證

  • 支持以下幾種認證:

    • HTTP Basic
    • HTTP Digest
    • Kerberos
    • NTLM
  • Swift

    	// Http basic 方式認證
    	
        	let user = "user"
        	let password = "password"
        
        	Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
    
            	.authenticate(user: user, password: password)
    
    	// NSURLCredential 方式認證
    	
        	let user = "user"
        	let password = "password"
        
        	let credential = NSURLCredential(user: user, password: password, persistence: .ForSession)
        
        	Alamofire.request(.GET, "https://httpbin.org/basic-auth/\(user)/\(password)")
    
            	.authenticate(usingCredential: credential)
    
    	// headers 方式認證
    	
        	let user = "user"
        	let password = "password"
        
        	let credentialData = "\(user):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
        	let base64Credentials = credentialData.base64EncodedStringWithOptions([])
        
        	let headers = ["Authorization": "Basic \(base64Credentials)"]
        
        	Alamofire.request(.GET, "https://httpbin.org/basic-auth/user/password", headers: headers)
    

5、Alamofire HTTP 響應狀態信息識別

  • Swift

    • 手動識別

      	/*
      			Alamofire 還提供了 HTTP 響應狀態的判斷識別,通過 validate 方法,對於在我們期望之外的 HTTP 響應狀態信息,
      		Alamofire 會提供報錯信息:
      	*/
      	
      	Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
              
      		.validate(statusCode: 200..<300)
              
      		.validate(contentType: ["application/json"])
      
    • 自動識別

      	// validate 方法還提供自動識別機制,我們調用 validate 方法時不傳入任何參數,則會自動認為 200…299 的狀態嗎為正常:
      
      	Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"])
              
      		.validate()
      

6、Alamofire Timeline

  • Swift

    	/*
    			Alamofire collects timings throughout the lifecycle of a Request and creates a Timeline object 
    		exposed as a property on a Response.
       	*/
       	
    	Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video", parameters: ["type": "JSON"])
    
      		.validate()
    
      		.responseJSON { response in
    
           	print(response.timeline)
    	}
    
    	The above reports the following Timeline info:
        
        	Latency: 0.428 seconds
        	Request Duration: 0.428 seconds
        	Serialization Duration: 0.001 seconds
        	Total Duration: 0.429 seconds
    

7、Alamofire 調試打印

  • Swift

    	// GET print
    	
        	let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
        
        	print(request)
    
    		// 打印輸出 GET http://192.168.88.200:8080/MJServer/video?type=JSON
      	
    	// POST print
    	
        	let request = Alamofire.request(.POST, "http://192.168.88.200:8080/MJServer/video", parameters: ["type":"JSON"])
        
        	print(request)
    
    		// 打印輸出 POST http://192.168.88.200:8080/MJServer/video
       	
    	// GET debugprint
    	 
        	let request = Alamofire.request(.GET, "http://192.168.88.200:8080/MJServer/video?type=JSON")
        
        	debugPrint(request)
    
    		// 打印輸出 curl 信息
    
        	$ curl -i \
             	-H "User-Agent: SwiftAlamofire/com.qianqianstudio.SwiftAlamofire (1; OS Version 9.3 (Build 13E230))" \
             	-H "Accept-Language: zh-Hans-US;q=1.0, en-US;q=0.9" \
             	-H "Accept-Encoding: gzip;q=1.0, compress;q=0.5" \
             		"http://192.168.88.200:8080/MJServer/video?type=JSON"
    

8、Alamofire 網絡連接狀態檢查

  • Swift

    	網絡連接狀態:
     
         	public enum NetworkReachabilityStatus {
             	case Unknown            網絡狀態未知
             	case NotReachable       無網絡連接
             	case Reachable(Alamofire.NetworkReachabilityManager.ConnectionType)
         	}
        
         	public enum ConnectionType {
             	case EthernetOrWiFi     WiFi 網絡
             	case WWAN               無線網絡(蜂窩移動網絡)
         	}
       	
    	let manager = NetworkReachabilityManager()
        
      	// 監聽網絡狀態閉包
    	manager?.listener = { status in
            
    		/*
        		開啟網絡狀態監聽后,只要網絡狀態發生改變就會調用該閉包代碼段。
    	 	*/
          
    		print("Network Status Changed: \(status)")
    	}
       
       	// 開啟監聽網絡狀態
    	manager?.startListening()
      
      	// 關閉網絡狀態監聽
    	manager?.stopListening()
       
       	// 獲取網絡連接狀態
    	let status = manager?.networkReachabilityStatus
      	
      	// 判斷網絡是否連接
    	let isReachable:Bool? = manager?.isReachable
      	
      	// 判斷 WiFi 是否連接
    	let isReachableOnEthernetOrWiFi:Bool? = manager?.isReachableOnEthernetOrWiFi
      	
      	// 判斷 無線網絡 是否連接
    	let isReachableOnWWAN:Bool? = manager?.isReachableOnWWAN
    

9、Alamofire 異步 GET 數據請求

  • Swift

    	// Alamofire 方式
        
        	let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
    
        	Alamofire.request(.GET, urlStr)
        
            	.response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
    
                	/*
    					網絡請求結束,成功時 error == nil。請求返回的數據存在 responseData 中,為 NSData 格式。
                	*/
            	}
    	
    	// Manager 方式
        
        	// 必須設置為全局的
    		var alamofireManager: Manager!
        
        	let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video?type=XML"
    
        	self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
        
        	self.alamofireManager.request(.GET, urlStr)
            
            	.response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
                
                	/*
                 		網絡請求結束,成功時 error == nil。請求返回的數據存在 responseData 中,為 NSData 格式。
                 	*/
            	}
    

10、Alamofire 文件下載

  • 支持的類型:

    • Request
    • Resume Data
  • 默認支持后台方式下載

  • Swift

    • 指定文件路徑方式

      	// 目標路徑閉包展開
      
      	Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
      	                  { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
      
      		/*
      				設置文件下載路徑,temporaryURL 是沙盒下的文件臨時存儲路徑,下載完成后會被自動刪除。response.suggestedFilename 
      			為服務器端文件名。此 block 在子線程中執行。
      		*/
          
      		let documentsDirUrl:NSURL = NSFileManager.defaultManager()
      		                                         .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
      		                                         .URLByAppendingPathComponent(response.suggestedFilename!)
          
      		if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
              
              	// 移除已經存在的文件,在 Swift 中文件已經存在時,再次相同路徑寫入會失敗
              	try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)                
      		}	
      
      		return documentsDirUrl
      	}
      
      		.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
              
      			/*
      				監聽文件下載進度,此 block 在子線程中執行。
      			*/
              	
              	// 設置下載進度條 
      			let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
      			self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
      		}
          
      		.response { (_, _, _, error:NSError?) in
      
      			/*
      				網絡請求結束,成功時 error == nil。在 Swift 中文件已經存在時,再次相同路徑寫入會失敗。
      			*/	
      		}
      
    • 使用默認提供的下載路徑方式

      	// 目標路徑閉包
          	
          	// 設置文件的默認下載路徑
          	let destination = Alamofire.Request.suggestedDownloadDestination(directory: .DocumentDirectory, domain: .UserDomainMask)
          	
          	Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4", destination: destination)
              	
              	.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
               	
                  	/*
      					監聽文件下載進度,此 block 在子線程中執行。
                  	*/
                  
                  	// 設置下載進度條
                  	let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                  	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                  	                      withObject: progressNum, 
                  	                   waitUntilDone: true)
              	}
              	
              	.response { (_, _, _, error:NSError?) in
      			
                  	/*
                      	網絡請求結束,成功時 error == nil。在 Swift 中文件已經存在時,再次相同路徑寫入會失敗。
                  	*/
      			}
      
    • 斷點續傳下載方式

      	// 使用斷點下載需要之前下載的臨時文件存在,才能繼續下載。
      
      	var downloadRequest:Request!
      	var resumeData:NSData!
      
      	// 開始下載
      	
          	let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true)[0] + "/resumeData.tmp"
          
          	// 判斷斷點保存的文件是否存在
          	if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
      
          		// 斷點開始下載
          	
              	// 讀取斷點保存的數據
              	self.resumeData = NSData(contentsOfFile: resumeTmpPath)
      
              	self.downloadRequest = Alamofire.download(resumeData: self.resumeData, destination: 
              	                                 { (temporaryURL:NSURL, response:NSHTTPURLResponse) -> NSURL in
                  	
                 	let documentsDirUrl:NSURL = NSFileManager.defaultManager()
                 	                                         .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
                 	                                         .URLByAppendingPathComponent(response.suggestedFilename!)                   
                  	if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
                      
                  		try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
                  	}
                  	
                  	return documentsDirUrl
              	})
      
                 	.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
                      	
                     	let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
                     	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                     	                      withObject: progressNum, 
                     	                   waitUntilDone: true)
                  	}
                  
                  	.response { (_, _, data:NSData?, error:NSError?) in
                      	
                      if error == nil {
                          
                         	// 刪除斷點下載緩存文件
                          
                        	let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
                        	                                                        .UserDomainMask, 
                        	                                                        true)[0] 
                        	                                                      + "/resumeData.tmp"
                          
                        	if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
                         		try! NSFileManager.defaultManager().removeItemAtPath(resumeTmpPath)
                        	}
                          	
                     	} else {
                          
                         	// 下載的臨時文件不存在處理
                              
                       	if error?.localizedFailureReason == "No such file or directory" {
                                  
      							let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
      							                                                        .UserDomainMask, 
      							                                                        true)[0]
      							                                                      + "/resumeData.tmp"
                                
      							if NSFileManager.defaultManager().fileExistsAtPath(resumeTmpPath) {
                                      
      								// 刪除斷點下載緩存文件,否則繼續斷點下載會報錯
      								try! NSFileManager.defaultManager().removeItemAtPath(resumeTmpPath)
      							}	
      						}
      					}
      				}
          	} else {
              
              	// 重新開始下載
              	
      			self.resumeData = NSData()
              
      			self.downloadRequest = Alamofire.download(.GET, "http://120.25.226.186:32812/resources/videos/minion_01.mp4") 
              	                                         { (temporaryURL:NSURL, response: NSHTTPURLResponse) -> NSURL in
                  
      				let documentsDirUrl:NSURL = NSFileManager.defaultManager()
      				                                         .URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
      				                                         .URLByAppendingPathComponent(response.suggestedFilename!)
      
      					if NSFileManager.defaultManager().fileExistsAtPath(documentsDirUrl.path!) {
                          
      						try! NSFileManager.defaultManager().removeItemAtURL(documentsDirUrl)
      					}
                  
      					return documentsDirUrl
      			}
      
      				.progress { (bytesWrite:Int64, totalBytesWrite:Int64, totalBytesExpectedToWrite:Int64) in
                      
      					let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesWrite)/Double(totalBytesExpectedToWrite)))
      					self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
      					                      withObject: progressNum, 
      					                   waitUntilDone: true)
      				}
      
      				.response { (_, _, data:NSData?, error:NSError?) in
                      
      					if error == nil {
                          
      					} else {
                          
      						// 停止下載處理
      				
      						if error!.code == NSURLErrorCancelled {
                              
      							if data != nil {
                                  
      								// 意外終止的話,把已下載的數據儲存起來
      								self.resumeData = data
                                  
      								let resumeTmpPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, 
      								                                                        .UserDomainMask, 
      								                                                        true)[0] 
      								                                                      + "/resumeData.tmp"
                                  
      								self.resumeData.writeToFile(resumeTmpPath, atomically: true)
      							}
                              	
      						} else {
                              	
      					}
      				}
      			}
      		}
      
      	// 暫停下載
      	
        		self.downloadRequest.suspend()
       		
      	// 繼續下載
      	
        		self.downloadRequest.resume()
         	
      	// 停止下載
      	  
        		self.downloadRequest.cancel()
      

11、Alamofire 異步 POST 數據請求

  • Swift

    • Alamofire 方式

      	let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
      	let parameters:[String: AnyObject]? = ["type":"XML"]
      
      	Alamofire.request(.POST, urlStr, parameters: parameters)
      
      		.response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
      
      			/*
      				網絡請求結束,成功時 error == nil。請求返回的數據存在 responseData 中,為 NSData 格式。
      			*/	
      		}
      
    • Manager 方式

      	// 必須設置為全局的
      	var alamofireManager: Manager!
      
      	let urlStr:URLStringConvertible = "http://192.168.88.200:8080/MJServer/video"
      	let parameters:[String: AnyObject]? = ["type":"XML"]
      
      	self.alamofireManager = Manager(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
      
      	self.alamofireManager.request(.POST, urlStr, parameters: parameters)
          
          	.response { (request:NSURLRequest?, response:NSHTTPURLResponse?, responseData:NSData?, error:NSError?) in
              
              	/*
                  	網絡請求結束,成功時 error == nil。請求返回的數據存在 responseData 中,為 NSData 格式。
               	*/	
          	}
      

12、Alamofire 文件上傳

  • 支持的類型:

    • File
    • Data
    • Stream
    • MultipartFormData
  • Swift

    • Data 形式上傳

      	let boundary = "myBoundary"
      
      	// 設置請求頭
      	/*
      		upload task 不會在請求頭里添加 content-type (上傳數據類型)字段,@"myBoundary" 為請求體邊界,參數可以隨便設置,但需一致
      	*/
      	let headers = ["Content-Type":"multipart/form-data; charset=utf-8; boundary=\(boundary)"]
      
      	// 設置請求文件參數
      
          	let formBody = NSMutableData()
          
          	// 參數開始分割線
          	/*
          		每個參數開始前都需要加
          	*/
          	formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 參數
          	/*
          		username 是后台規定的參數名,jhq 是需要添加的參數內容值
          	*/
          	formBody.appendData("Content-Disposition: form-data; name=\"\("username")\"\r\n\r\n\("jhq")"
          	        .dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 文件開始分割線
          	/*
          		每個文件開始前都需要加
          	*/
          	formBody.appendData("--\(boundary)".dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 文件參數名
          	/*
          		file 是后台規定的參數名,test.mp4 為上傳后服務器端文件名稱
          	*/
          	formBody.appendData("Content-Disposition: form-data; name=\"\("file")\"; filename=\"\("test.mp4")\""
          	        .dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 文件的類型
          	formBody.appendData("Content-Type: mp4".dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 待上傳文件數據
          	/*
          		本地待上傳的文件路徑
          	*/
        		formBody.appendData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
          
          	// 結束分割線標記
          	formBody.appendData("--\(boundary)--".dataUsingEncoding(NSUTF8StringEncoding)!)
          	formBody.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!)
      
      	Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", headers: headers, data: formBody)
          
          	.progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
              
              	/*
                  	監聽文件上傳進度,此 block 在子線程中執行。
               	*/
              
              	let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
              	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), withObject: progressNum, waitUntilDone: true)
          	}
          
          	.response { (_, _, responseData:NSData?, error:NSError?) in
              
              	/*
                  	網絡請求結束。
               	*/	
          	}
      
    • MultipartFormData 形式上傳

      	Alamofire.upload(.POST, "http://192.168.88.200:8080/MJServer/upload", 
      	                        multipartFormData: { (formData:MultipartFormData) in
          
          	/*
              	添加參數。第一個參數是需要添加的參數內容值,第二個是后台規定的參數名。
           
              	設置上傳的文件。第一個參數是需要上傳的文件路徑,第二個是后台規定的參數名,第三個是上傳后服務器端文件名稱,第四個是文件類型。
           	*/
          
          	// 添加參數
          
              	formData.appendBodyPart(data: "jhq".dataUsingEncoding(NSUTF8StringEncoding)!, name: "username")
          
          	// 指定文件路徑形式上傳
          
              	let fileUrl = NSBundle.mainBundle().URLForResource("HQ_0005", withExtension: "jpg")!
          
              	formData.appendBodyPart(fileURL: fileUrl, name: "file", fileName: "test.png", mimeType: "image/jpeg")
          
          	// 指定文件數據形式上傳
          
              	let fileData = NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("minion", ofType: "mp4")!)
          
              	formData.appendBodyPart(data: fileData!, name: "file", fileName: "test.mp4", mimeType: "mp4")
          
      	}) { (encodingResult:Manager.MultipartFormDataEncodingResult) in
          
          	/*
              	數據編碼完成。
           	*/
          
          	switch encodingResult {
              
              	// 編碼成功
              	case .Success(let uploadRequest, _, _):
      
                  	uploadRequest
      
      					.progress { (bytesLoad:Int64, totalBytesLoad:Int64, totalBytesExpectedToLoad:Int64) in
                          
                        	/*
                         		監聽文件上傳進度,此 block 在子線程中執行。
                         	*/
                          
                       	let progressNum:NSNumber = NSNumber(float: Float(Double(totalBytesLoad)/Double(totalBytesExpectedToLoad)))
                       	self.performSelectorOnMainThread(#selector(ViewController.refreshProgress(_:)), 
                       	                      withObject: progressNum, 
                       	                   waitUntilDone: true)
                     	}
                      
                     	.response { (_, _, responseData:NSData?, error:NSError?) in
                          
                       	/*
                           	網絡請求結束。
                        	*/	
                      }
              
              	// 編碼失敗
              	case .Failure(let error):
                  	
                  	print(error)
          	}
      	}
      


免責聲明!

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



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