• 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:@"%@
    ",MPboundary];
            //添加字段名称,换2行
            [body appendFormat:@"Content-Disposition: form-data; name="%@"
    
    ",key];
            //添加字段的值
            [body appendFormat:@"%@
    ",[postParems objectForKey:key]];
        }
        if(picFileName){
            
            ////添加分界线,换行
            [body appendFormat:@"%@
    ",MPboundary];
            
            //声明pic字段,文件名为boris.png
            [body appendFormat:@"Content-Disposition: form-data; name="%@"; filename="%@"
    ",FORM_FLE_INPUT,picFileName];
            //声明上传文件的格式
            NSString * formant = [NSString stringWithFormat:@"Content-Type:%@
    
    ",format];
            [body appendFormat:@"%@", formant];
        }
        
        
        //声明结束符:--AaB03x--
        NSString *end=[[NSString alloc]initWithFormat:@"
    %@",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;
    }
  • 相关阅读:
    关于Java8:StreamAPI的一点记录
    关于JDBC的批量操作executeBatch()所引发sql语句异常
    [Java]直播方案----[接入环信聊天室]+[腾讯云直播]
    获取SpringCloud gateway响应的response的值,记录踩坑
    Spring Boot2.1.7启动zipkin-server报错:Error creating bean with name 'armeriaServer' defined in class path
    java.lang.IllegalArgumentException: Prometheus requires that all meters with the same name have the same set of tag keys.
    Spring Cloud Gateway报错:Unable to start embedded Tomcat
    poi设置Word页边距
    访问rabbitmq-server失败
    RabbitMQ获取队列的消息数目
  • 原文地址:https://www.cnblogs.com/zhangxiaoxu/p/6824011.html
Copyright © 2020-2023  润新知