前言html
最近在公司写了个小程序来为iOS应用中的图片瘦身,进而减少APP大小,减小用户下载时的流量。json
瘦身是在一个专门为图片瘦身的网站进行的。小程序
地址:https://tinypng.com安全
这个网站提供的接口是基于https协议的,以前没有怎么用过https协议,如今一并总结一下。服务器
关于HTTPS多线程
https协议基础请参考参考:app
其实HTTPS就是安全版本的http协议,async
他采用了RSA非对称加密公私钥对,使用SSL证书验证保证了用户数据在传输时的安全行。网站
下面简单看一下http和https请求过程的异同
咱们按个看下流程
1.客户端向服务端发送基于https的请求。
2.服务端建立公私钥对。
3.服务端把共钥绑定在证书上面返回给客户端。
4.客户端验证证书是否可靠(验证方式有两种,分别针对CA机构办法的证书和本身建立的证书:1.是向颁发证书的CA机构发送请求来验证。2.是在客户端保存一个证书副本,来对比两个证书,同时还会验证是否被中间人进行了攻击,验证方式就是用证书的pubkey去解证书的上密文,若是和证书上的明文一直就能够肯定没有被攻击)。
5.客户端生成一个随机数并用公钥加密传递给服务器。
6.服务器用私钥解密获得随机数,根据随机数产生对称加密秘钥并用私钥对秘钥进行加密。
7.传递对称秘钥给客户端。
8.客户端用公钥解密获得对称加密秘钥。
之后的通讯就会使用对称加密的秘钥来进行了,因此https其实也就第一次请求会比较慢,由于要生成通讯对称秘钥,之后再进行通讯就和http不会差不少了。
iOS对于HTTPS的支持
在说这点以前,先说说tinypng这个网站的接口。
注册新用户后会返回给你一串key,咱们要针对这串key作https请求
该站采用的是HTTP Basic Auth认证方式(关于Basic Auth认证方式详情参看维基百科)。
因此咱们作请求的时候就须要使用添加headerfield。
返回的时候会把咱们上传图片处理后的下载路径传回来,比较奇葩的是,路径并不在响应体而是在响应头中的Location字段内...(难道图片就不须要保密了么...)。
下面说说iOS该怎么作,
iOS的NSURLConnection和NSURLSession的API都提供了很方便的API来支持https请求。
我在实际操做的时候使用的是NSURLConnection。
首先建立请求:
1 NSURL *url = [NSURL URLWithString:REQUEST_URL]; 2 3 NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; 4 5 NSString *basicAuthUsername = BASIC_AUTH_USERNAME; 6 NSString *basicAuthPassword = BASIC_AUTH_PASSWORD; 7 NSData *authorizationData = [[NSString stringWithFormat:@"%@:%@",basicAuthUsername,basicAuthPassword] dataUsingEncoding:NSASCIIStringEncoding]; 8 NSString *authorizationStr = [NSString stringWithFormat:@"Basic %@",[authorizationData base64EncodedStringWithOptions:0]]; 9 NSLog(@"%@",authorizationStr); 10 [request setHTTPMethod:@"POST"]; 11 [request addValue:authorizationStr forHTTPHeaderField:@"Authorization"]; 12 [request addValue:@"*/*" forHTTPHeaderField:@"Accept"];
URL在API中提供的有,只是协议咱们写为HTTPS,而后进行Authorization头字段的拼接,实际上就是Basic base64(用户名:密码)。
Accept这里设置为了*/*,其实若是知道服务器返回类型能够直接指定application/json或者text/json之类的就行。
下面看看链接:
1 -(BOOL)connection:(NSURLConnection*)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace*)protectionSpace 2 { 3 return[protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; 4 } 5 6 -(void)connection:(NSURLConnection*)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge 7 { 8 [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; 9 }
咱们须要实现NSURLConnectionDelegate,而后实现上面的两个方法。
第一个方法是判断须要响应哪一类的安全问题,
NSString *NSURLAuthenticationMethodDefault;
NSString*NSURLAuthenticationMethodHTTPBasic;
NSString*NSURLAuthenticationMethodHTTPDigest;
NSString*NSURLAuthenticationMethodHTMLForm;
NSString*NSURLAuthenticationMethodNegotiate;
NSString*NSURLAuthenticationMethodNTLM;
NSString*NSURLAuthenticationMethodClientCertificate;
NSString*NSURLAuthenticationMethodServerTrust;
能够响应的安全问题有不少,这里咱们只响应HTTPS相关的就行,所以选择NSURLAuthenticationMethodServerTrust。
第二个方法是处理验证结果的,这里我这样写会直接忽略证书验证,这里咱们能够处理证书的验证策略逻辑。
咱们start connection后就会发现能够成功的调用接口了。
关于一些其余细节
写这个小玩意仍是用到了一些没有接触过的东西的。
下面总结一下。
1.文件实例类NSFileHandle,这个类能够拿到文件实例,好比咱们想去控制文件读写细节就须要用到这个类,这里使用是为了保存没有成功请求的图片名称。
2.connection的异步请求作的很是好了,使用多线程请求,具体的请求线程个数由系统来判断。
3.多线程读写文件使用dispatch_barrier_async方法避免资源竞争。
不足
1.写的时候是全部上传请求所有结束后才开始下载的,这样效率很低,能够修改成成功上传后就直接下载不用等待其余的文件上传,不过这样多线程处理会稍微麻烦一些。