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