前言
最近在公司寫了個小程序來為iOS應用中的圖片瘦身,進而減小APP大小,減少用戶下載時的流量。
瘦身是在一個專門為圖片瘦身的網站進行的。
這個網站提供的接口是基于https協議的,之前沒有怎么用過https協議,現在一并總結一下。
關于HTTPS
https協議基礎請參考參考:
其實HTTPS就是安全版本的http協議,
他采用了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*)protectionSpace2 {3 return[protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];4 }5 6 -(void)connection:(NSURLConnection*)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge7 {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.寫的時候是所有上傳請求全部結束后才開始下載的,這樣效率很低,可以修改為成功上傳后就直接下載不用等待其他的文件上傳,不過這樣多線程處理會稍微麻煩一些。
新聞熱點
疑難解答