写在前面:

在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;
}

Telegram学习解析系列(二):这我怎么给后台传输数据?的更多相关文章

  1. Telegram学习解析系列(一):认识一下Telegram的源码

    前言: Telegram不知道有多少同行听过这玩意,或者在看它的源码.我是出于工作原因才接触到这东西,看的真是的......变方了!一个月估计刚刚找到门,还没进去多深,把自己的心得和对源码的认识以及我 ...

  2. Telegram学习解析系列(三) : Build Telegram报错分析总结

    正好通过这次 Telegram 的运行,很想把常见的项目运行的错误好好的总结一下,在前面的博客中,又星星散散的总结过错误和一些警告的消除方法,这次把错误处理一下,还有Telegram项目中有999+的 ...

  3. java基础解析系列(二)---Integer

    java基础解析系列(二)---Integer 前言:本系列的主题是平时容易疏忽的知识点,只有基础扎实,在编码的时候才能更注重规范和性能,在出现bug的时候,才能处理更加从容. 目录 java基础解析 ...

  4. ETL利器Kettle实战应用解析系列二

    本系列文章主要索引如下: 一.ETL利器Kettle实战应用解析系列一[Kettle使用介绍] 二.ETL利器Kettle实战应用解析系列二 [应用场景和实战DEMO下载] 三.ETL利器Kettle ...

  5. Socket学习总结系列(二) -- CocoaAsyncSocket

    这是系列的第二篇 这是这个系列文章的第二篇,要是没有看第一篇的还是建议看看第一篇,以为这个是接着第一篇梳理的 先大概的总结一下在上篇的文章中说的些内容: 1. 整理了一下做IM我们有那些途径,以及我们 ...

  6. ETL利器Kettle实战应用解析系列二 【应用场景和实战DEMO下载】

    本文主要阅读目录如下: 1.应用场景 2.DEMO实战 3.DEMO下载 1.应用场景 这里简单概括一下几种具体的应用场景,按网络环境划分主要包括: 表视图模式:这种情况我们经常遇到,就是在同一网络环 ...

  7. 小白学习Spark系列二:spark应用打包傻瓜式教程(IntelliJ+maven 和 pycharm+jar)

    在做spark项目时,我们常常面临如何在本地将其打包,上传至装有spark服务器上运行的问题.下面是我在项目中尝试的两种方案,也踩了不少坑,两者相比,方案一比较简单,本博客提供的jar包适用于spar ...

  8. 学习CNN系列二:训练过程

    卷积神经网络在本质上是一种输入到输出的映射,它能够学习大量的输入与输出之间的映射关系,而不需要任何输入和输出之间精确的数学表达式,只要用已知的模式对卷积神经网络加以训练,网络就具有输入.输出之间映射的 ...

  9. Dubbo源码学习总结系列二 dubbo-rpc远程调用模块

    dubbo本质是一个RPC框架,我们首先讨论这个骨干中的骨干,dubbo-rpc模块. 主要讨论一下几部分内容: 一.此模块在dubbo整体框架中的作用: 二.此模块需要完成的需求功能点及接口定义: ...

随机推荐

  1. 初识vuex

    1.简介 vuex是 vue官方推荐的一个状态管理器.当我们遇到很多状态改变时,组件之间的通信就会变得复杂,这时候vuex的强大就展现出来. 我们从vuex的原理以及vuex的api两个部分介绍vue ...

  2. wamp虚拟服务器

    1.安装好wampServer 2.修改配置文件包含 vhosts 文件,操作: 打开apache的配置文件httpd.conf,并去掉#Include conf/extra/httpd-vhosts ...

  3. JS调用WebService,发布到IIS,网页提示WebService未定义[已解决]

    VS2013中,JS调用WebService,一直运行正常.部署到WindowsServer2008之后,在网页中访问,始终提示网页中有错误,点开之后发现是WebService未定义. 于是上网查解决 ...

  4. python之函数学习

    #!/usr/bin/env python # # =============================================== # 位置参数说明 # 位置参数 通过参数传递的位置来 ...

  5. Intellj IDEA 简易教程

    Intellj IDEA 简易教程 目录 JDK 安装测试 IDEA 安装测试 调试 单元测试 重构 Git Android 其他 参考资料 Java开发IDE(Integrated Developm ...

  6. python操作数据库之批量导入

    python操作数据库之批量导入 Python语法简洁清晰,特色之一是强制用空白符(white space)作为语句缩进. Python具有丰富和强大的库.它常被昵称为胶水语言,能够把用其他语言制作的 ...

  7. 【转】关于swf安全沙箱冲突:不能被本地访问

    错误提示:SWF 文件不能被本地访问 不能访问本地只有仅限于文件系统的 SWF 文件和可信的本地 SWF 文件可以访问本地资源 错误信息:SecurityError:Error #2148: SWF ...

  8. C#中关于WebBrowser的一些细节设置

    在winform中有一个控件可以显示html的内容,该控件就是webbrowser,设置它的DocumenText属性为HTML的内容即可. 在使用WebBrowser做UI的时候,我们有时不希望里面 ...

  9. 如何在IDEA中调试 Jar文件

    原创文章,转载请注明出处:http://www.cnblogs.com/acm-bingzi/p/6668333.html   问题: 一般情况下,可以打成Jar包的项目,它的源码运行Applicat ...

  10. ORA-00918: 未明确定义列

    ORA-00918: 未明确定义列 出现问题原因及解决办法. --正常写,结果带上表名的字段在处理后表头名称相同,在进行下一次嵌套时就会出现问题  select au.userxm,au01.user ...