AFNetworking 3.x 使用心得

作者: lyy0905 | 来源:发表于2016-09-28 16:44 被阅读0次

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];

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

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

相关文章

  • AFNetworking 3.x 使用心得

    AFNetworking毫无疑问是目前iOS开发中(Objective-C)最好的第三方网络库。一般规模的app使...

  • 收集优秀的第三方

    网络请求 1、AFNetworking2、AFNetworking 3.x 与YYCache封装,一句代码搞定数据...

  • AFNetworking 3.X 简单使用

    一、网络请求: GET方式: POST方式: 二、文件上传: 通过工程中的文件上传 根据URL路径上传 三、文件下...

  • AFNetworking源码分析(1)

    首先,AFNetworking是基于CFNetwork封装的。相对于3.x之前的版本,3.x摒弃了以前的NSURL...

  • AFNetworking 3.x 调用

    AFNetworking 3.x是基于NSURLSession再次封装的 大致结构如下: NSURLSession...

  • AFNetworking-数据流程

    AFNetworking AFNetWorking基本上是所有iOS项目的标配。现在升级带最新版的3.X了。得益于...

  • iOS 初探 AFNetworking

    本文不对AFNetworking作全面的解析,仅对比解析一下2.x和3.x的差异。 AFNetworking分为如...

  • iOS 初探 AFNetworking

    本文不对AFNetworking作全面的解析,仅对比解析一下2.x和3.x的差异。 AFNetworking源码分...

  • 苹果开发三方技能包收藏

    1>PPNetworkHelper AFNetworking 3.x 与YYCache封装,一句代码搞定数据请求与...

  • AFNetworking 3.x

    AFNetworking2.0源码解析<一> AFNetworking2.0源码解析<二>-- 构建普通请求: 格...

网友评论

    本文标题:AFNetworking 3.x 使用心得

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