AFNetworking 3.x 使用心得

AFNetworking毫无疑问是目前iOS开发中(Objective-C)最好的第三方网络库。一般规模的app使用AFNetworking就可以完成所有需求,不需要自己造轮子。
在使用AFNetworking的过程中遇到了许多坑,也获得了不少经验,在这里总结一下,希望能够帮助到大家。

AFNetworking进一步封装

AFNetworking 3.x 已经为我们提供了丰富而且易用的API,但还是不够。AFNetworking是一个通用的库,而在我们自己的项目中,有特定的需求,而且往往在许多类中都需要用到网络请求。对AFNetworking进一步封装,能够大大简化代码,减少重复。
举个例子,新建一个CDMNetworkManager类,继承AFHTTPSessionManager。

//CDMNetworkManager.h
#import <AFNetworking/AFNetworking.h>

typedef void(^requestSuccessBlock) (NSURLSessionTask *task, id resposeObject);
typedef void(^requestFailureBlock) (NSURLSessionTask *task, NSError *error);

@interface CDMNetworkManager : AFHTTPSessionManager
+(instancetype)sharedManager;
-(void)sendPostRequest:(NSString *)path parameters:(NSDictionary *)parameters success:(requestSuccessBlock)success failure:(requestFailureBlock)failure;
//CDMNetworkManager.m
#import "CDMNetworkManager.h"

typedef void(^requestSuccessBlock) (NSURLSessionTask *task, id resposeObject);
typedef void(^requestFailureBlock) (NSURLSessionTask *task, NSError *error);

@implementation CDMNetworkManager

+(instancetype)sharedManager{
    static CDMNetworkManager *manager = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
       manager = [[self alloc] initWithBaseURL:[NSURL URLWithString:@"http://www.someurl.com/"]];

    });
    return manager;
}

-(void)sendPostRequest:(NSString *)path parameters:(NSDictionary *)parameters success:(requestSuccessBlock)success failure:(requestFailureBlock)failure{
    [self POST:path parameters:parameters progress:nil success:^(NSURLSessionTask *task, id responseObject){
        success(task,responseObject);
    } failure:^(NSURLSessionTask *task, NSError *error){
        failure(task,error);
    }];
}

初始化方法中使用了单例模式,这样与服务器的连接不会断掉,省去了每次建立连接时三次握手等过程。如果有多个URL地址,可以创建多个单例。如果有更多特殊的要求,比如设置超时时间等,可以在这个方法中设置。
具体的网络请求方法这里只封装了一个简单的post方法,如果有需要可以封装别的方法。
调用的时候很简单,在任何一个需要发送post请求的类中:

[[CDMNetworkManager sharedManager] sendPostRequest:@"XXX" parameters:parameter success:^(NSURLSessionTask *task, id responseObject){
        //your code
    } failure:^(NSURLSessionTask *task, NSError *error){
        // your code
    }];

调试工具

曾经我每次网络请求调试的时候只会在回调里写log,然后在控制台里一行一行的仔细查找。如果这个请求返回的内容很多,在Xcode里的显示效果就很差,而且不能直接显示中文。体验很差!

这时候需要神器Charles

上面是Charles的截图,能够监听Mac的所有网络请求并且显示各种格式的内容,非常好用。如果用模拟器的话就可以直接用Charles抓包,如果真机调试的话,需要设置一下iPhone,网上也有很多教程。
虽然是付费软件,但是不买license只是打开时会有10秒延时,每隔30分钟自动关闭。

常见错误

Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html"

出现这个问题的原因有很多,从表面上看是返回数据的格式不支持text/html,但是为什么返回了text/html?原因不唯一。
首先要看请求的response code,如果是200,说明请求已经传到服务器并且成功返回,返回的格式是text/html。AFNetworking的默认response serializer是AFJSONResponseSerializer,不支持text/html。
这时需要在manager的初始化方法中增加一下代码。或者与服务器开发人员沟通,改写服务器端。

manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];

如果response code是400,说明服务器根本没有收到请求。这时为什么返回了一个text/html的数据呢?返回的数据在Xcode控制台上显示为16进制,但是在Charles里我们可以看到结果

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>请求错误</title>
    <style>BODY { color: #000000; background-color: white; font-family: Verdana; margin-left: 0px; margin-top: 0px; } #content { margin-left: 30px; font-size: .70em; padding-bottom: 2em; } A:link { color: #336699; font-weight: bold; text-decoration: underline; } A:visited { color: #6699cc; font-weight: bold; text-decoration: underline; } A:active { color: #336699; font-weight: bold; text-decoration: underline; } .heading1 { background-color: #003366; border-bottom: #336699 6px solid; color: #ffffff; font-family: Tahoma; font-size: 26px; font-weight: normal;margin: 0em 0em 10px -20px; padding-bottom: 8px; padding-left: 30px;padding-top: 16px;} pre { font-size:small; background-color: #e5e5cc; padding: 5px; font-family: Courier New; margin-top: 0px; border: 1px #f0f0e0 solid; white-space: pre-wrap; white-space: -pre-wrap; word-wrap: break-word; } table { border-collapse: collapse; border-spacing: 0px; font-family: Verdana;} table th { border-right: 2px white solid; border-bottom: 2px white solid; font-weight: bold; background-color: #cecf9c;} table td { border-right: 2px white solid; border-bottom: 2px white solid; background-color: #e5e5cc;}</style>
  </head>
  <body>
    <div id="content">
      <p class="heading1">请求错误</p>
      <p xmlns="">服务器处理请求时遇到错误。有关构造有效服务请求的内容,请参阅<a rel="help-page" href="http://www.zjubiomedit.com:13264/HypertensionService.svc/help">服务帮助页</a>。</p>
    </div>
  </body>
</html>

这是自动返回的一个错误页面,而不是服务器返回的数据格式不对。这时候再去找response serializer的问题就南辕北辙了。

那么为什么服务器没有受到请求?
一种可能是baseURL的问题。AFHTTPSessionManager的初始化中用到了baseURL,与之后的path拼接时可能出错,检查一下。
还有可能是request serializer的问题。AFNetworking默认的是AFHTTPRequestSerializer。如果服务器接受的参数只能是json的话,需要使用AFJSONRequestSerializer。

self.requestSerializer = [AFJSONRequestSerializer serializer];

可能还有其他各种各样奇怪的原因,欢迎大家补充。

作者时间、能力有限,文章难免有不足之处,请大家指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,292评论 4 61
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,773评论 19 139
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,689评论 7 249
  • 目录|每一刻都是崭新的 上一章 文|于一潇 7、 商业街越来越旺了,辛月的时光咖啡书吧也跟着旺了起来。每到周末,辛...
    于一潇阅读 3,034评论 12 9
  • 大家好!给大家介绍一下,这是我新出炉的男朋友……@樱空释 其实还有待细化细节……可是画着画着,竟然有初恋的影子重叠...
    笑语浅兮阅读 4,151评论 0 3