Telegram學習解析系列(二):這我怎么給后台傳輸數據?


寫在前面:

         在iOS開發的過程中,有很多時候我們都在和數據打交道,最基本的就是數據的下載和上傳了,估計很多很多的小伙伴都在用AFNetworking與后台數據打交道,可有沒有想過,哪天AFNetworking你不能用了或者不會用了怎么辦?可能你心中疑惑了,這三方只要更新,存在怎么會不能用或者我怎么會不會用了,在沒有看Telegram源碼之前,我也是這么想的,看了Telegram源碼就不會再這么想了,以后我會把自己看的Telegram源碼部分的總結和經驗一點點的整理分享出來,整理成這個Telegram學習解析系列,有興趣的同行可以加文章鏈接最后面的telegram開發學習群,一起學習討論Telegram問題,Android和iOS都可以。一起進步!

需求怎樣來的?

        先看看這個,在Telegram的安全協議 MtProtoKit中,你可以看到這個Third Party 這個文件,看下面的截圖:

       可以看到這里面是有AFNetworking的,這個框架里面的東西有寫就是集成字AF來寫的,但AF這個版本是挺低的,嘗試着自己在這個基礎上去寫上傳那些方法應該是可以,我嘗試過之后放棄了,還是決定利用 NSURLConnection / NSURLSessionDataTask來自己寫,不過這個的話就的涉及到了請求這些東西的一個封裝,以及利用這個上傳圖片或者語音什么的時候,還有里面的參數的一個組裝,接下來就認真的把這部分的東西寫出來,這也是在Telegram的基礎上衍生出來的問題,要是平常的項目中,可能也不會輕易涉及到這些東西,既然用到了就好好總結一下:

一:簡單的數據訪問

       先從簡單的開始,就從你給后台Post數據開始,先從NSURLConnection開始,下面的代碼就是具體的實例,每一句都有具體的注釋,看代碼:

 -(NSString * )httpRequestWithParameters:(NSDictionary*)dict andURL:(NSURL*)url{
 
         //把參數字典轉化成Data
         NSData * postData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:NULL];
         //把Data利用這個Key加密,這個Key自己設置
         NSString * key = @"********";
         postData = [postData AES256_Encrypt:key];
         //初始化request
         NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
         //設置請求方式
         [request setHTTPMethod:@"POST"];
         //添加請求體,這里要進行64編碼處理,就是這個newStringInBase64FromData方法
         [request setHTTPBody:[[postData newStringInBase64FromData] dataUsingEncoding:NSUTF8StringEncoding]];
         //設置請求的報文
         [request setValue:@"utf-8" forHTTPHeaderField:@"charset"];
         [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
         //請求超時時間設置
         [request setTimeoutInterval:15.0];
         
         NSOperationQueue * queue = [[NSOperationQueue alloc]init];
         [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse * response, NSData *data, NSError *error){
 
                 if(error){
                     NSLog(@"文本內容上傳失敗");
                     NSLog(@"%@",data);
                     NSLog(@"%@",response);
                 }else{
                    // 解析服務器返回的數據(解析成字符串)
                    NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                    NSLog(@"解析服務器返回的數據====%@", string);
                 }
         }];
 }

注意:關於配置報文下面這篇文章   POST請求的forHTTPHeaderField   感謝作者。

           上面方法那些編碼、加密方法,你要有需要的話可以在我首頁找到我Q,我發給你。

          上面的方法你可以給后台去POST數據,再說剩下的這個 NSURLSessionDataTask ,其實蘋果是不建議使用前面的 NSURLConnection 了的,這個我們就說的簡單點,你怎么從后台請求數據,下面就但是一個簡單的Get方法,請求Request部分的我們就不說了,和上面的一樣,參考上面的就行,下面就是一個完整的方法,你通過請求獲取到數據回調的方法:

-(void)httpRequestWithURL:(NSURL*)url andHttpRequestSuccess:(HttpRequestSuccess)httpRequestSuccess  andHttpRequestFail:(HttpRequestFail)httpRequestFail{
        
     //推薦使用這種請求方法,上面的方已經被廢棄
     //下面的方法沒有給Request設置請求頭和內容,有需要參考上面的寫法
     NSURLSession * session = [NSURLSession sharedSession];
     NSURLSessionDataTask * dataTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                
       if (!error) {
         //沒有錯誤,返回正確
         NSError * jsonError;
         NSDictionary * dic =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&jsonError];
         if (!jsonError) {
             httpRequestSuccess(dic);
         }
       }else{
         //請求出現錯誤
         httpRequestFail(@"請求錯誤");
       }
       NSLog(@"response==%@",response);
    }];
    [dataTask resume];
}

上面的這些就把簡單的怎樣和后台進行數據交互就解決了,當然這試試簡單的,涉及到文件下載上傳的我們就下面接着說:

二 :涉及到文件類型的怎么處理

       下面這個方法是在處理Telegram消息類型上傳數據給后台的時候添加的,這個方法可能里面納西而判斷等等的東西你用不着,主要的你看里面上傳部分的內容封裝吧,主要的還是這部分的東西,或者對這個方法里面還有什么疑問的,可以問我。方法我直接給出來,里面的注釋真的挺詳細的了。一句一句的過:

/**
 上傳Data

 @param url           上傳DataUrl
 @param postParems    參數
 @param picFilePath   文件路徑
 @param picFileName   文件名稱,
 @param message_Type  消息類型(區分你要上傳的文件是什么類型的,圖片、視頻、語音等等)
 @param fileName      這是像PDF,TXT等格式問文件的文件名
 @return return value description
 */
+ (NSString *)postRequestWithURL: (NSString *)url postParems: (NSMutableDictionary *)postParems picFilePath: (NSString *)picFilePath picFileName: (NSString *)picFileName  andMessageType:(Message_Type)message_Type andFileName:(NSString *)fileName{
    
    /**
     boundary: 是分隔符號,告訴服務器,我的請求體里用的就是就是這個分隔符,而且,拼接請求體也用到這個分隔符
     */
    NSString *TWITTERFON_FORM_BOUNDARY = @"iOSFileUploaded";
    //根據url初始化request
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                                           cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                       timeoutInterval:10];
    //分界線 --AaB03x
    NSString *MPboundary=[[NSString alloc]initWithFormat:@"--%@",TWITTERFON_FORM_BOUNDARY];
    //結束符 AaB03x--
    NSString *endMPboundary=[[NSString alloc]initWithFormat:@"%@--",MPboundary];
    
   
    NSData * data;
    NSString * format; // 文件上傳的格式
    //得到圖片的data
    if (message_Type == ImageMessage) {
        
        format = @" image/jpge,image/gif, image/jpeg, image/pjpeg, image/pjpeg";
        UIImage *image=[UIImage imageWithContentsOfFile:picFilePath];
        //返回為JPEG圖像
        data = UIImageJPEGRepresentation(image, 0.3f);
        
    //得到語音或者視頻的data
    }else if (message_Type == VoiceMessage){
    
        format = @"audio/mp3";
        data= [NSData dataWithContentsOfFile:picFilePath];
    }else if (message_Type == VedioMessage){
    
        format = @"audio/mp4";
        [self convertVideoWithModel:picFilePath andUrl:url andNSDictionary:postParems];
        return @"進入了視頻壓縮";
    }else if (message_Type == PasterMessage){
        
        format = @"image/webp";//webp圖片格式
        data = [NSData dataWithContentsOfFile:picFilePath];
    }else if (message_Type == FileMessage){
        
         format = [self GetContentType:fileName]; //判斷文件的上傳格式,利用后綴名判斷
         data   = [NSData dataWithContentsOfFile:picFilePath];
    }
    // 在這里判斷Data是否存在
    if (!data) {
        
        NSLog(@"要上傳的data不存在");
        return @"data不存在";
    }
    //http body的字符串
    NSMutableString *body=[[NSMutableString alloc]init];
    //參數的集合的所有key的集合
    NSArray *keys= [postParems allKeys];
    //遍歷keys
    for(int i=0;i<(int)[keys count];i++){
        //得到當前key
        NSString *key=[keys objectAtIndex:i];
        //添加分界線,換行
        [body appendFormat:@"%@\r\n",MPboundary];
        //添加字段名稱,換2行
        [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
        //添加字段的值
        [body appendFormat:@"%@\r\n",[postParems objectForKey:key]];
    }
    if(picFileName){
        
        ////添加分界線,換行
        [body appendFormat:@"%@\r\n",MPboundary];
        
        //聲明pic字段,文件名為boris.png
        [body appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n",FORM_FLE_INPUT,picFileName];
        //聲明上傳文件的格式
        NSString * formant = [NSString stringWithFormat:@"Content-Type:%@\r\n\r\n",format];
        [body appendFormat:@"%@", formant];
    }
    
    
    //聲明結束符:--AaB03x--
    NSString *end=[[NSString alloc]initWithFormat:@"\r\n%@",endMPboundary];
    //聲明myRequestData,用來放入http body
    NSMutableData *myRequestData=[NSMutableData data];
    
    //將body字符串轉化為UTF8格式的二進制
    [myRequestData appendData:[body dataUsingEncoding:NSUTF8StringEncoding]];
    if(data){
        
        [myRequestData appendData:data];
    }
    //加入結束符--AaB03x--
    [myRequestData appendData:[end dataUsingEncoding:NSUTF8StringEncoding]];
    
    //設置HTTPHeader中Content-Type的值
    NSString *content=[[NSString alloc]initWithFormat:@"multipart/form-data; boundary=%@",TWITTERFON_FORM_BOUNDARY];
    //設置HTTPHeader
    [request setValue:content forHTTPHeaderField:@"Content-Type"];
    //設置Content-Length
    [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[myRequestData length]] forHTTPHeaderField:@"Content-Length"];
    //設置http body
    [request setHTTPBody:myRequestData];
    //http method
    [request setHTTPMethod:@"POST"];
    
    NSHTTPURLResponse *urlResponese = nil;
    NSError * error = [[NSError alloc]init];
    NSData  * resultData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponese error:&error];
    
    NSDictionary * JSONresponseObject = [NSJSONSerialization JSONObjectWithData:resultData options:NSJSONReadingMutableContainers error:nil];
    if ([[NSString stringWithFormat:@"%@",JSONresponseObject[@"errorCode"]] isEqualToString:@"0"]) {
        
        NSString *string = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
        NSLog(@"解析服務器返回的字符串====%@", string);
        NSLog(@"解析服務器返回的字典  ====%@", JSONresponseObject);
        return @"200";
    }
    return nil;
}

        為了不讓博客篇幅太長,上面涉及到的視頻壓縮,還有文件的后綴名的判斷方法就不在發出來了,到時這個消息類型的判斷,這個我覺得是有必要發出來的,不是說這個有多復雜,只是可能找起來沒那么容易能找打一份完整的,既然能看到這,估計可能有伙伴會有需要的:

/*** 根據文件類型判斷上傳的文件格式 ***/
+(NSString*)GetContentType:(NSString*)filename{
    
    // 判斷之前先把文件名稱轉化成小寫
    NSString * Filename = [filename lowercaseString];
    
    if ([Filename hasSuffix:@"avi"]) {
    
        return @"video/avi";
    }
    else if([Filename hasSuffix:@"bmp"])
    {
        return @"application/x-bmp";
    }
    else if([Filename hasSuffix:@"jpeg"])
    {
        return @"image/jpeg";
    }
    else if([Filename hasSuffix:@"jpg"])
    {
        return @"image/jpeg";
    }
    else if([Filename hasSuffix:@"png"])
    {
        return @"image/x-png";
    }
    else if([Filename hasSuffix:@"mp3"])
    {
        return @"audio/mp3";
    }
    else if([Filename hasSuffix:@"mp4"])
    {
        return @"video/mpeg4";
    }
    else if([Filename hasSuffix:@"rmvb"])
    {
        return @"application/vnd.rn-realmedia-vbr";
    }
    else if([Filename hasSuffix:@"txt"])
    {
        return @"text/plain";
    }
    else if([Filename hasSuffix:@"xsl"])
    {
        return @"application/x-xls";
    }
    else if([Filename hasSuffix:@"xslx"])
    {
        return @"application/x-xls";
    }
    else if([Filename hasSuffix:@"xwd"])
    {
        return @"application/x-xwd";
    }
    else if([Filename hasSuffix:@"doc"])
    {
        return @"application/msword";
    }
    else if([Filename hasSuffix:@"docx"])
    {
        return @"application/msword";
    }
    else if([Filename hasSuffix:@"ppt"])
    {
        return @"application/x-ppt";
    }
    else if([Filename hasSuffix:@"pdf"])
    {
        return @"application/pdf";
    }
    return nil;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM