文档章节

使用AFNetworking框架遇到的一个经典bug的解决方案

DXSmile_大熊
 DXSmile_大熊
发布于 2016/03/04 00:24
字数 1469
阅读 58
收藏 2
点赞 1
评论 0

以上为个人愚见, 如有不妥,望大家斧正!!! 本文的GitHub源码下载地址: https://github.com/DXSmile/Bug---AFNetworking.git

如需转载,请注明转载自DXSmile的 GitHub项目https://github.com/DXSmile/Bug---AFNetworking.git

##阐述: 在获取网络数据的时候, 我们一般会使用到一个非常著名的框架: AFNetworking框架, 可以说,这是作为iOS攻城狮必备的框架之一; 这个框架是非常强大的一个框架, 对于发送异步请求来说,简直没有比这个更好用的了, 不过,在使用的过程中,我们可能会遇到这样一个bug: 如下

连接出错 Error Domain=com.alamofire.error.serialization.response Code=-1016 
"Request failed: unacceptable content-type: text/html" UserInfo=
{com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7f93fad1c4b0> 
{ URL: http://c.m.163.com/nc/article/headline/T1348647853363/0-140.html } 
{ status code: 200, headers { .....}
...... 
 22222c22 626f6172 64696422 3a226e65 77735f73 68656875 69375f62 6273222c 22707469 6d65223a 22323031 362d3033 2d303320 31313a30 323a3435 227d5d7d>,
 NSLocalizedDescription=Request failed: unacceptable content-type: text/html}

####说明: 由于数据很多,所以返回的请求体,和响应体部分我用省略号(......)代替了, 但是,通过上面的返回的信息,我们不难看出,状态码是200, 而且也有一堆数据, 但是在tableviewCell中就是没有显示, 在最后的时候还出现"NSLocalizedDescription=Request failed: unacceptable content-type: text/html} " 这样一句话;

分析:那么这个错误是什么原因造成的呢?

通过这句话:unacceptable content-type: text/html,我们可以看出报错原因:是不接收的内容类型,也就是说AFNetworking框架不支持解析text/html这种格式. 那么怎样解决呢?

首先我们需要明白: AFNetworking为什么能够解析服务器返回的东西呢?

因为manager有一个responseSerializer属性.它只设置了一些固定的解析格式.其中不包含text/html这种数据的格式.因为解析报错了. 我们来看一下AFNetworking解析格式的底层:

 self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];

通过底层,我们也可以看见,确实是没有text/html这种数据的格式的,

#####那如何解决这个问题呢? 错误的解决方法 下面我尝试了三种方法:

解决方法1: 直接给acceptableContentTypes属性添加类型

解决之前:

 self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];

解决之前

着手解决:

   AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManagermanager];

    // 添加 text/html 类型到可接收内容类型中
    mgr.responseSerializer.acceptableContentTypes= [NSSetsetWithObjects:@"text/html", nil];

运行结果: 解决之后:

通过执行结果可以很明显的看得出,我们已经非常成功的获取到了数据;

对方法1的思考:

**首先,我们可以明显的看出,方法1确实是可以解决问题的,但是这样解决真的好吗? 不一定! 为什么呢? 很简单, 如果我们只是发送一条网络请求,无疑方法1是最恰当的解决方案了, 但是实际开发中,我们不可能只发一次请求, 那么就需要我们每次发请求的时候都来写一次这些代码; 当然,如果您愿意写,那我也没办法多说什么了; 很显然,这个方法是存在不足的! **

于是我们有了第二种方法:

解决办法2: 直接到框架的源代码中添加类型

解决之前:

 self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];

解决之后:

 self.acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"application/json", @"text/json" ,@"text/javascript", nil];
分析方法2:

不得不说,这也是一种办法, 而且釜底抽薪,效果方面呢,当然也是显而易见了, 但是, 注意了,这个方法2 又真的恰当吗? 真的好吗?

我们来假设一种情况, 而且实际开发中必然会发生的情况: 这个框架更新了!!! 对,就是更新了!!! 更新了显然又会回到之前的状态 傻眼了吧? ** 实际开发中,我们都会用cocoaPods来管理我们的第三方框架, 当某个框架更新之后, cocoaPods会下载最新的框架源码镶嵌到我们的项目中, 我们并不能保证AFNetworking这个框架一定会把我们需要的类型添加上去, 所以每一次更新,我们都需要针对源码再做一次修改** 很显然,这也是费力不讨好的;

那么有没有一劳永逸的方法呢? 别急,马上就来!!!

解决办法3: 自定义一个manager ,拓展一个类型

>>这里需要考虑到两种情况: 如下
>1. 如果你的APP只需要适配iOS7.0之前的版本,为了能够适配旧系统,需要使用 AFHTTPRequestOperationManager
>2. 如果你的APP只需要适配iOS7.0之后的版本,那么你需要 自定义的类是继承AFHTTPSessionManager的

这里我只简单的介绍iOS7.0之后的版本,

1> 自定义manager,继承自AFHTTPSessionManager

@interface DXHTTPManager : AFHTTPSessionManager

2> 在.m文件中,重写父类的manager方法 目的 : 添加类型

+ (instancetype)manager {
    DXHTTPManager *mgr = [super manager];
    // 创建NSMutableSet对象
    NSMutableSet *newSet = [NSMutableSet set];
    // 添加我们需要的类型 
    newSet.set = mgr.responseSerializer.acceptableContentTypes;
    [newSet addObject:@"text/html"];
    
    // 重写给 acceptableContentTypes赋值
    mgr.responseSerializer.acceptableContentTypes = newSet;
    
    return mgr;
}

3> 在发送请求的时候,使用我们自定义的类来发送请求

[[DXHTTPManager manager] GET:@"http://...." 
parameters:nil success:^(AFHTTPRequestOperation *operation, NSDictionary * responseObject) 
{
    NSLog(@"请求成功 -- %@",responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"请求失败 -- %@",error);
}];

执行结果:

方法3执行结果:

结论:

使用方法3来解决这个bug,虽然看似比第一种,第二种要繁琐一些,实则可拓展性,和维护方面,要好得多,以后我们开发项目的时候, 只需要将我们自定义的这个类拖进去就可以了, 假如有需要新的类型的时候, 也只是简单的多配置一下类型即可, 而这也正是我们代码重构, 和优化项目架构的思路之一!!!

© 著作权归作者所有

共有 人打赏支持
DXSmile_大熊
粉丝 9
博文 22
码字总数 28308
作品 0
海淀
项目经理
iOS源码补完计划--AFNetworking 3.1.0源码研读

参拜一下AFNetworking的源码。 第四篇源码、暂时来看也是iOS方向的最后一篇、撸完准备趁着热乎撸一撸网络协议。 目录 准备工作 功能模块 AFURLSessionManager/AFHTTPSessionManager AFNetwo...

kirito_song ⋅ 05/25 ⋅ 0

iOS源码补完计划--AFNetworking(一)

目录 前言 AFURLSessionManager AFHTTPSessionManager API注释Demo 参考 前言 AFNetworking第一篇 主要看了看AFURLSessionManager以及AFHTTPSessionManager相关的API AFN概述:《iOS源码补完计...

kirito_song ⋅ 05/15 ⋅ 0

iOS源码补完计划--AFNetworking(二)

目录 前言 AFNetworkReachabilityManager.h AFNetworkReachabilityManager.m API注释Demo 参考资料 前言 AFNetworking源码第二篇 主要看了看AFNetworkReachabilityManager的内容 作为一个辅助...

kirito_song ⋅ 05/16 ⋅ 0

AFNetworking实现原理理解

NSURLSession: NSURLSession由三个基本模块构成: NSURLSession NSURLSessionConfiguation NSURLSessionTask NSURLSession相对于平时通信中的会话,但本身却不会进行网络数据传输,它会穿件多...

法斗斗 ⋅ 05/09 ⋅ 0

iOS源码补完计划--AFNetworking(三)

目录 前言 AFSecurityPolicy.h AFSecurityPolicy.m 参考资料 前言 AFNetworking源码第三篇 主要看了看AFSecurityPolicy的内容 负责网络安全策略(证书)的验证 作为一个辅助模块、代码量和文件...

kirito_song ⋅ 05/17 ⋅ 0

iOS源码补完计划--AFNetworking(五)

目录 前言 核心代码 APIDemo 参考资料 前言 AFNetworking源码第五篇、大概也是最后一篇 主要看了看AFURLResponseSerialization的内容 负责网络请求成功之后服务器返回的响应体进行格式化 代码...

kirito_song ⋅ 05/25 ⋅ 0

iOS源码补完计划--AFNetworking(四)

目录 前言 流程图 核心代码 请求头 请求体 AFHTTPRequestSerializer APIDemo 参考资料 前言 AFNetworking源码第四篇 主要看了看AFURLRequestSerialization的内容 负责网络请求NSMutableURLR...

kirito_song ⋅ 05/23 ⋅ 0

iOS Reachability检测网络状态

一、整体介绍 前面已经介绍了网络访问的NSURLSession、NSURLConnection,还有网页加载有关的webview,基本满足通常的网络相关的开发。 其实在网络开发中还有比较常用的就是网络状态的检测。苹...

robslove ⋅ 05/06 ⋅ 0

swift4,网络请求工具Moya

在OC中,我们使用AFNetworking来进行网络请求,简洁方便。在swift中,我们使用Moya来进行网络请求,Moya封装了Alamofire,可以更加方便的进行网络请求。初次使用Moya,还是觉得稍稍有些不习惯...

小曼Study ⋅ 05/29 ⋅ 0

iOS底层探究-Runloop

Runloop 1. 概述 一般来说,一个线程只能执行一个任务,执行完就会退出,如果我们需要一种机制,让线程能随时处理时间但并不退出,那么 RunLoop 就是这样的一个机制。Runloop是事件接收和分发...

极客学伟 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java的Excel导出工具类

首先在POM中引入需要的Jar <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><dependency><groupId>o......

Kxvz ⋅ 3分钟前 ⋅ 0

Java 3DES加密解密

import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.binary.Base64; //算法代码[java] view plain copy /** * 转换成十六进制字......

说回答 ⋅ 9分钟前 ⋅ 0

php 浮点型计算精度问题

今天碰到一个金额计算的问题,浮点数做差,结果有误(精度有问题)。 $a = floatval('6');$b = floatval('4.99');$m = floatval('1');$r = $a - $b;$r = $r - $m;var_dump($r);//f...

stupidboy ⋅ 31分钟前 ⋅ 0

Mahout推荐算法之SlopOne

一、 算法原理 有别于基于用户的协同过滤和基于item的协同过滤,SlopeOne采用简单的线性模型估计用户对item的评分。如下图,估计UserB对ItemJ的偏好 图(1) 在真实情况下,该方法有如下几个...

xiaomin0322 ⋅ 36分钟前 ⋅ 0

LVM讲解

LVM是什么 LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制,Linux用户安装Linux操作系统时遇到的一个常见的难以决定的问题就是如何正确地...

李超小牛子 ⋅ 45分钟前 ⋅ 0

mysql更改密码、连接mysql、mysql常用命令

1. 更改mysql的root账户密码: mysql中root账户和系统root不是一个账户 1.1 更改环境变量PATH,增加mysql绝对路径 由于mysql安装目录为/usr/local/mysql/,所以系统不能直接使用mysql,需把/...

laoba ⋅ 47分钟前 ⋅ 0

阿里云发布企业数字化及上云外包平台服务:阿里云众包平台

摘要: 阿里云正式发布旗下众包平台业务(网址:https://zhongbao.aliyun.com/),支持包括:网站定制开发,APP、电商系统等软件开发,商标、商品LOGO、VI、产品包装设计、营销推广、大数据人...

猫耳m ⋅ 47分钟前 ⋅ 0

阿里云发布企业数字化及上云外包平台服务:阿里云众包平台

摘要: 阿里云正式发布旗下众包平台业务(网址:https://zhongbao.aliyun.com/),支持包括:网站定制开发,APP、电商系统等软件开发,商标、商品LOGO、VI、产品包装设计、营销推广、大数据人...

阿里云云栖社区 ⋅ 50分钟前 ⋅ 0

1.03-Maven中使用ueditor富文本编辑器

起因:在maven仓库未找到百度的ueditor的jar包 操作: 1.下载百度的ueditor的jar包 2.打开命令行,切换到ueditor的下载位置,运行一下命令: mvn install:install-file -Dfile=ueditor-1.1....

静以修身2025 ⋅ 56分钟前 ⋅ 0

几道Spring 面试题

1、BeanFactory 接口和 ApplicationContext 接口有什么区别? ApplicationContext 接口继承BeanFactory接口 Spring核心工厂是BeanFactory BeanFactory采取延迟加载,第一次getBean时才会初始...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部