前言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.寫的時候是全部上傳請求所有結束後纔開始下載的,這樣效率很低,能夠修改成成功上傳後就直接下載不用等待其餘的文件上傳,不過這樣多線程處理會稍微麻煩一些。