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



|
1
|
import Alamofire |
二,使用Alamofire进行数据请求
|
1
|
|
|
1
|
|
|
1
2
3
4
5
6
7
8
9
10
11
|
.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还提供了许多其他类型的响应处理方法:
responseData()
responseString(encoding: NSStringEncoding)
responseJSON(options: NSJSONReadingOptions)
responsePropertyList(options: NSPropertyListReadOptions)
(2)Response Handler
|
1
2
3
4
5
6
7
|
.response { request, response, data, error in print(request) print(response) print(data) print(error) } |
(3)Response Data Handler
|
1
2
3
4
5
6
|
.responseData { response in print(response.request) print(response.response) print(response.result) } |
(4)Response String Handler
|
1
2
3
4
5
|
.responseString { response in print("Success: \(response.result.isSuccess)") print("Response String: \(response.result.value)") } |
(5)Response JSON Handler
使用responseJSON自动解析son数据:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
.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
|
.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
|
|
4,请求参数(Parameters)
(1)使用GET类型请求的时候,参数会自动拼接在url后面
|
1
2
|
|
(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 ]]// 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" ]]// HTTP body: {"foo": [1, 2, 3], "bar": {"baz": "qux"}} |
服务端php页面可以这么取得发送过来的JSON数据:
|
1
2
3
4
5
6
7
8
|
<?$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"] .responseJSON { response in debugPrint(response) } |
三,判断数据请求是否成功,并做相应的处理
在请求响应对象之前调用的 .validate() 函数是另一个易用的 Alamofire 特性。
将其与请求和响应链接,以确认响应的状态码在默认可接受的范围(200到299)内。如果认证失败,响应处理方法将出现一个相关错误,我们可以根据不同在完成处理方法中处理这个错误。
比如下面的样例,成功时会打印成功信息,失败时输出具体错误信息。
|
1
2
3
4
5
6
7
8
9
10
|
.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
|
print(request)/********** 下面是控制台输出 *********************************************************/ |
|
1
2
3
4
5
6
7
8
9
10
|
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
|
.responseString { response in debugPrint(response)}/********** 下面是控制台输出 ***************SUCCESS: { "args": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip;q=1.0,compress;q=0.5", "Accept-Language": "zh-Hans-CN;q=1.0,en-CN;q=0.9", "Host": "httpbin.org", "User-Agent": "hangge_970/com.hangge.hangge-970 (1; OS Version 9.1 (Build 13B137))" }, "origin": "180.109.163.139", }******************************************/ |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
.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", }******************************************/ |
1,Alamofire支持如下上传类型:
Data
Stream
MultipartFormData
2,使用文件流的形式上传文件
|
1
2
3
|
let fileURL = NSBundle.mainBundle().URLForResource("hangge", withExtension: "zip") |
附:服务端代码(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)){ } 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") .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) } |
可以看到控制台不断输出已上传的数据大小:

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)//文件1let path = NSBundle.mainBundle().pathForResource("hangge", ofType: "png")!let file1Data = NSData(contentsOfFile: path)//文件2let 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"]);?> |
1,自定义下载文件的保存目录
|
1
2
3
4
5
6
7
8
9
|
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
|
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) destination: destination) |
3,下载进度
下面代码在文件下载过程中会不断地打印下载进度,同时下载完成后也会打印完成信息。
|
1
2
3
4
5
6
7
8
9
10
11
|
let destination = Alamofire.Request.suggestedDownloadDestination( directory: .DocumentDirectory, domain: .UserDomainMask) .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
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 UIKitimport Alamofireclass 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() }} |
HTTP Digest
Kerberos
NTLM
本文讲解使用 Alamofire 进行 HTTP Basic 验证。
(1)HTTP Basic认证是允许HTTP服务器对WEB浏览器进行用户身份证的方法。
(3)HTTP服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64加密的用户名和密码),解开请求包,对用户名及密码进行验证,
如果用户名及密码正确,则根据客户端请求,返回客户端所需要的数据。否则,返回错误代码或重新要求客户端提供用户名及密码。
HTTP基本认证只提供简单的用户验证功能,优点是使用简单,适合于对安全性要求不高的系统或设备中。
比如:路由器的配置页面就常使用HTTP Basic认证。(浏览器输入路由器ip地址,如192.168.1.1,这时就会弹出个用户密码输入框进行权限验证。)
(1)没有灵活可靠的认证策略,如无法提供域(domain或realm)认证功能。
(2)BASE64 的加密强度非常低。当然,HTTP基本认证系统也可以与SSL或者Kerberos结合,实现安全性能较高(相对)的认证系统。
为了测试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页面,则会弹出对话框要求输入用户名和密码:

如果输入正确的用户名(hangge)和密码(123)则返回正常的数据,否则返回错误信息并需要继续输入:

6,客户端代码
|
1
2
3
4
5
6
7
8
9
|
let user = "hangge"let password = "123" .authenticate(user: user, password: password) .responseString { response in // debugPrint(response) print(response.result.value)} |
从控制台打印的消息可以看出,认证通过,并成功获取到数据:

Swift:网络库Alamofire的更多相关文章
- Swift网络库Alamofire的导入
一.手动导入 1, 官网下载 Alamofire 2, 解压下载的文件 放入工程的顶层目录下 3, 打开工程 Add Files 4, 选中项目 TARGETS > General > E ...
- 网络库Alamofire使用方法学习笔记
Github地址 由于Alamofire是swift网络库,所以,以下的所有介绍均基于swift项目 导入Alamofire 以下为使用cocoapods导入,其余的方式请参考官网 source 'h ...
- 网络库Alamofire使用方法
Github地址 由于Alamofire是swift网络库,所以,以下的所有介绍均基于swift项目 导入Alamofire 以下为使用cocoapods导入,其余的方式请参考官网 source 'h ...
- swift三方库
链接: Swift 有哪些优秀的第三方库? Swift 中AFNetworking 的替代方案 Alamofire Swift2.0后Alamofire的使用方法 [快速学会Swift第三方库] Al ...
- swift中第三方网络请求库Alamofire的安装与使用
swift中第三方网络请求库Alamofire的安装与使用 Alamofire是swift中一个比较流行的网络请求库:https://github.com/Alamofire/Alamofire.下面 ...
- Alamofire网络库进阶教程
本章节由CocoaChina翻译组成员星夜暮晨(博客)翻译自raywenderlich:Intermediate Alamofire Tutorial,敬请勘误. 欢迎回到我们的 Alamofire ...
- Swift 网络请求数据与解析
一: Swift 网络数据请求与处理最常用第三方 又有时间出来装天才了,还是在学swift,从中又发现一些问题,这两天上网找博客看问题弄的真的心都累.博客一篇写出来,好多就直接照抄,就没有实质性的把问 ...
- swift网络数据请求方法
搭建一个apache服务器,用php编写一个返回给客户端请求数据的脚本 <?php // header("Content-type:text/html;charset=utf-8&qu ...
- 33 个 2017 年必须了解的 iOS/swift 开源库第三方库
本文翻译自Medium,原作者为 Paweł Białecki<img src="https://pic3.zhimg.com/v2-c786777447261347b0d97 ...
随机推荐
- Java并发编程:阻塞队列(转载)
Java并发编程:阻塞队列 在前面几篇文章中,我们讨论了同步容器(Hashtable.Vector),也讨论了并发容器(ConcurrentHashMap.CopyOnWriteArrayList), ...
- JS回调函数(callback)
在使用Jquery的时候,用到Callback(),回调函数的概念.而且很多. 比如: $.ajax({ url:"test.json", type: "GET" ...
- Bag of mice(CodeForces 148D )
D. Bag of mice time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...
- long型转日期型
//时分秒格式//不知为何,出来的时间有点差别 public class Test { public static void main(String[] args) throws Exception ...
- tomcat 集群配置,Session复制共享
本配置在tomcat7上验证通过.通过此方法配置的集群,session信息将会被自动复制到各个节点. 1.配置Server.xml 在Server.xml中,找到被注释<Cluster/> ...
- 如何实现ASP.NET中网站访问量的统计
如何实现ASP.NET中网站访问量的统计 2009-07-30 15:50 佚名 网翼教程网 字号:T | T 本文介绍了如何在asp.net中进行网站访问量的统计. AD:51CTO 网+ 第十二期 ...
- "QQ尾巴病毒"核心技术的实现原理分析
声明:本文旨在探讨技术,请读者不要使用文章中的方法进行任何破坏. 2003这一年里,QQ尾巴病毒可以算是风光了一阵子.它利用IE的邮件头漏洞在QQ上疯狂传播.中毒者在给别人发信息时,病毒会自动在信息文 ...
- CentOS linux 下eclipse+cdt编译报undefined reffrece to *
- POJ 1860 Currency Exchange 最短路 难度:0
http://poj.org/problem?id=1860 #include <cstdio> //#include <queue> //#include <deque ...
- C# JObject解析Json(多方法解析Json 二)
下载Newtonsoft.Json,添加引用 记得using Newtonsoft.Json.Linq; //用JObject解析 string json = "{\"offlin ...