美文网首页网络请求
基于afnetwork3.0的webservice请求

基于afnetwork3.0的webservice请求

作者: 可齐 | 来源:发表于2016-06-20 15:06 被阅读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
    

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

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

    相关文章

      网友评论

      • 呵呵哈哈嘿嘿:你好,在soapMessage中的agent和soapenv分别代表什么?
      • 呵呵哈哈嘿嘿:WebService有认证账号和密码,iOS进行请求改怎么设置?
      • 清蒸鱼跃龙门:我公司的项目用的是AF第一代,以后万一出啥问题都不知道怎么办,升级也是个大问题。学习iOS的时候用的是2.*的AF,主要以session为主,旧的主要以connection为主,如果升级cocoapods,旧的很多都不能用了 。要改底层,头疼。。
        可齐:@清蒸鱼跃龙门 AF升级这个问题,其实核心都没什么变化。你可以考虑封装网络层方法的,这样改起来也比较容易。建议你尝试一下升级3.* 。因为框架内部本身提升还是比较大的。
      • 云画的跃光:为什么我的没有用?快被折磨疯了
        云画的跃光:@Ritalina 有demo吗?
        可齐:@云画的跃光 不好意思,最近没上简书,才看到
        可齐:@云画的跃光 有报错吗,soapUI测试过吗
      • 多飞:好东西要多写,哈哈 :+1:
        可齐:@多飞 :v:

      本文标题:基于afnetwork3.0的webservice请求

      本文链接:https://www.haomeiwen.com/subject/kkmwdttx.html