网络请求

基于afnetwork3.0的webservice请求

2016-06-20  本文已影响558人  可齐

关于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

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

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

上一篇下一篇

猜你喜欢

热点阅读