基于afnetwork3.0的webservice请求

关于webservice

必须承认,在移动端做webservice请求是一件很痛苦的事情——复杂的请求体拼接,缓慢的xml格式解析。
但是,在实际工作中,还是不可避免的遇到一些这样的情况,那么,让我们尽量的做到代码优雅吧,不要让soap请求打乱了本来的节奏。

基于熟悉和优雅的诉求,webservice请求,我们还是基于的AFNetwork去做。

核心问题在于:AFNetwork2.0中的AFHTTPRequestOperation已被废弃,如何使用AFHTTPSessionManager去修改HTTPBody。

好了,下面让我们一起看一下

什么是soap

求助baidu(要是懒得看,跳过这一大段):

简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简单的、基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WEB上交换结构化的和固化的信息。

基于类对象的传输协议。
SOAP封装(envelop),它定义了一个框架,描述消息中的内容是什么,是谁发送的,谁应当接受并处理它以及如何处理它们;
SOAP编码规则(encoding rules),它定义了一种序列化机制,用于表示应用程序需要使用的数据类型的实例;
SOAP RPC表示(RPC representation),它定了一个协定,用于表示远程过程调用和应答;
SOAP绑定(binding),它定义了SOAP使用哪种协议交换信息。使用HTTP/TCP/UDP协议都可以。
把SOAP绑定到HTTP提供了同时利用SOAP的样式和分散的灵活性的特点以及HTTP的丰富的特征库的优点。在HTTP上传送SOAP并不是说SOAP会覆盖现有的HTTP语义,而是HTTP上的SOAP语义会自然的映射到HTTP语义。在使用HTTP作为协议绑定的场合中,RPC请求映射到HTTP请求上,而RPC应答映射到HTTP应答。然而,在RPC上使用SOAP并不仅限于HTTP协议绑定。

——————自己理解————————

这是一种webservice协议,本质来说,还是HTTP请求呗,还是那个老样子,分为HTTPHeader和HTTPBody

AFNetwork封装的很好,所以很多人可能已经不了解底层,AFNetwork以及苹果的请求体只让你看到配置部分,不给你看到xml格式的请求体。但是现在,soap请求,请你自己拼HTTPBody

先去下载一个soapUI,这是一个非常强大的工具。把服务端给你的那个以?wdsl结尾的地址,放进去,可以读出所有的方法,以及你要去拼写的那个soap envelop(也就是信封)格式。点击运行,当然,你也可以查看运行结果。

soapui下载地址   http://www.soapui.org/

如果你必须要做soap接口请求了,务必下载!!!

1.关于NSMutableURLRequest

相信很多AFNetwork2.0访问webservice的例子中,都构建了NSMutableURLRequest,不赘述了,上代码

- (NSMutableURLRequest *)loadRequestWithParameter:(NSString *)parameter url:(NSString *)urlString methodName:(NSString *)methodName{

NSString *soapMessage =
[NSString stringWithFormat:
 @"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
 "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:agen=\"http://agent.water.tjswfxkh/\" >"
 "<soapenv:Body>"
 "<agen:%@>"
 "<arg0>%@</arg0>"
 "</agen:%@>"
 "</soapenv:Body>"
 "</soapenv:Envelope>", methodName,parameter,methodName
 ];

// 将这个XML字符串打印出来
NSLog(@"%@", soapMessage);
// 创建URL,内容是前面的请求报文报文中第二行主机地址加上第一行URL字段

NSURL *url = [NSURL URLWithString:urlString];
// 根据上面的URL创建一个请求
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSString *msgLengt = [NSString stringWithFormat:@"%ld", [soapMessage length]];
// 添加请求的详细信息,与请求报文前半部分的各字段对应
[req addValue:@"application/soap+xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[req addValue:msgLengt forHTTPHeaderField:@"Content-Length"];
// 设置请求行方法为POST,与请求报文第一行对应
[req setHTTPMethod:@"POST"];
// 将SOAP消息加到请求中
[req setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];

return req;
}

代码洁癖,封装了一个方法做这个事情。入参分别是参数、地址、soap方法名。这样我们就可以复用了,对不对。毕竟在同一个项目中,xml标签那部分,不是那么容易改变。

soapMessage的来源,就是soapUI中,说过的信封请求体,你只要保证和它拼的一样就ok,setHTTPBody会将这部分,加到request里。

2.AFHTTPSessionManager

进行到这一步,那么,怎么把request加载到SessionManager呢

在AFNetwork2.0中关于AFHTTPRequestOperation,是这样子的

 NSString *parameter = @"{\"endDate\":\"2015-06-01 08\",\"beginDate\":\"2015-06-01 08\"}";
NSString *urlStr = @"http://10.3.211.111/hw/cxf/water";
NSString *methodName = @"getSqInfo";

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:[self loadRequestWithParameter:parameter url:urlStr methodName:methodName]];

operation.responseSerializer = [AFXMLParserResponseSerializer serializer];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    
    //parse NSXMLParser object here if request successfull
    if ([responseObject isKindOfClass:[NSXMLParser class]]) {
        NSXMLParser *parser = (NSXMLParser *)responseObject;
        NSError *parseError = nil;
        NSDictionary *dict  = [XMLReader dictionaryForNSXMLParser:parser error:&parseError];
        NSLog(@"JSON: %@ - %@", responseObject,dict);
    }
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];
[[NSOperationQueue mainQueue] addOperation:operation];

AFHTTPRequestOperation被废弃后,AFNetwork3.0结合AFHTTPSessionManager

精华的部分来了!!!!

NSString *parameter = @"{\"endDate\":\"2015-06-01 08\",\"beginDate\":\"2015-06-01 08\"}";
NSString *urlStr = @"http://10.3.211.111/hw/cxf/water";
NSString *methodName = @"getSqInfo";


AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

//回复的序列化
manager.responseSerializer = [AFHTTPResponseSerializer serializer];

[[manager dataTaskWithRequest:[self loadRequestWithParameter:parameter url:urlStr methodName:methodName] completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {

    if (!error) {
        NSData * data = (NSData *)responseObject;
        
        NSXMLParser *parser = [[NSXMLParser alloc]initWithData:data];
        
        NSError *parseError = nil;
        NSDictionary *dict  = [XMLReader dictionaryForNSXMLParser:parser error:&parseError];
        NSLog(@"JSON: %@ - %@", responseObject,dict);
    } else {
        NSLog(@"Error: %@, %@, %@", error, response, responseObject);
    }

}] resume];

务必要加这句话,不然在返回xml格式response时候,会报错,进到error状态,但实际上HTTP请求state code=200,即请求已经成功。

manager.responseSerializer = [AFHTTPResponseSerializer serializer];

3.xml解析

上述代码经过本地服务的测试,已经跑通,不出意外的话,你会拿到一个NSData,解析后,是一个xml格式数据。
在这里用到了XMLReader,将其转换成了一个字典。

4.代码下载

演示代码已经上传,欢迎下载,希望能对大家有些帮助

https://github.com/Rita5969/afnetwork3.0-for-webservice

5.参考

非常非常感谢Pranoy C在stackoverflow贡献的答案

http://stackoverflow.com/questions/34561215/afnetworking-3-0-migration-how-to-post-with-headers-and-http-body

XMLReader-xml解析器

https://github.com/amarcadet/XMLReader

AFNetwork3.0迁移指南-官方Readme的中文翻译

http://www.jianshu.com/p/047463a7ce9b

———————————————————————————————————————————————————————————————————

如果大家对示例中的写法有好的建议,欢迎指正。后期如果有更好的方案,会继续更新。谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容