写在开头

  • 最近在思考最为客户端如何和后台进行数据交互,先是了解到了GET 和POST
  • 随后了解到了iOS有一个封装好的便携的上传数据的库AFNetWorking
  • 在这里记录一下简单的方法,接下来和后台进行数据交互的时候会用到
  • AFNetWorking 基本是iOS开发中使用网络通信框架的标配,这个框架本身比较庞大,也很复杂,但是使用起来非常非常简单,在这篇博客我简单的介绍我所需要用到的AFNetWorking的POST和GET的理解,如有错误,敬请指正。

GET 和POST

  • get和post是HTTP与服务器交互的方
  • PUT,DELETE,POST,GET 他们的作用分别是对服务器资源的增,删,改,查。
  • 简答的说:GET是获取数据,POST是修改数据

GET 和POST的区别联系

  • 据了解GET和POST都是HTTP协议中的两种发送请求的方法。由于并未学习到很深入,在这里简单了解了下主要的区别。
  • GET是从服务器上获取数据,POST是向服务器传送数据。
  • GET产生一个TCP数据包;POST产生两个TCP数据包
  • 对于GET方式的请求,浏览器会把http header和Data一并发送出去,服务器响应200(返回数据);
  • 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 才会(返回数据)。
  • 我的理解就是:对于GET只需要跑一趟就可以把数据传输到位,而POST则需要先去进行一个请求的过程,然后在把数据安排到位!
  • 重要的点:GET 安全性非常低,POST安全性较高。但是执行效率却比POST方法好。

AFNetWorking

  • AFNetWorking 基本是iOS开发中使用网络通信框架的标配,这个框架本身比较庞大,也很复杂,但是使用起来非常非常简单,在这篇博客我简单的介绍我所需要用到的AFNetWorking的POST和GET的理解,如有错误,敬请指正。
使用方法
  • AFNetWorking也是属于第三方库,我们需要pod该库
pod 'AFNetworking'

【iOS开发-AFNetWorking下的POST和GET】-LMLPHP

DEMO

  • 添加头文件
#import "AFNetworking.h"//主要用于网络请求方法
#import "UIKit+AFNetworking.h"//里面有异步加载图片的方法
  • 对于数据我用字典存储和上传
@interface ViewController ()
@property (nonatomic, strong)NSDictionary *AFNetWorkTestGETDictionary;
@property (nonatomic, strong)NSMutableDictionary *AFNetWorkTestPOSTDictionary;
@end

【iOS开发-AFNetWorking下的POST和GET】-LMLPHP

GET请求数据
  • 创建网络请求对象
  • 设置请求和接收的数据编码格式
  • 设置请求头 (没有可以不需要设置)
  • 请求地址
  • 请求参数
GET方法
  • 看一下AFNetWorking提供的GET方法及其参数
    【iOS开发-AFNetWorking下的POST和GET】-LMLPHP
  • 参数的理解
  •          第一个参数:NSString类型的请求路径,AFN内部会自动将该路径包装为													一个url并创建请求对象
      		 第二个参数:请求参数,此处为nil
      		 第三个参数:进度回调,此处为nil
      		 第四个参数:请求成功之后回调Block
      	     第五个参数:请求失败回调Block
    
- (void)GETNet {
    //创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 发送GET请求
    [manager GET:@"https://news-at.zhihu.com/api/4/news/before/20221023" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"GET 请求成功, %@", responseObject[@"date"]);
        self.AFNetWorkTestGETDictionary = responseObject;

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"GET 失败");
    }];
}

  • 这里我用知乎日报的URL进行测试,将GET到的数据存储到准备好的字典里面
  • self.AFNetWorkTestGETDictionary
 NSLog(@"%@", self.AFNetWorkTestGETDictionary);

【iOS开发-AFNetWorking下的POST和GET】-LMLPHP

GET请求到的数据解析
  • 这里就算是用GET方法请求成功了,对于AFN内部responseObject是请求成功返回的相应结果,在AFN内部已经把相应结果转换为OC对象,通常是字典或者数组,我直接进行了字典赋值
self.AFNetWorkTestGETDictionary = responseObject;

也可以这样

        // 转化为字典
        NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingMutableLeaves error:nil];
        
POST请求
  • AFN提供了POST的两种方法,由简单到复杂,这里以2个DEMO为例
[manager POST:(nonnull NSString *) parameters:(nullable id) headers:(nullable NSDictionary<NSString *,NSString *> *) progress:^(NSProgress * _Nonnull uploadProgress) {
        ;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        ;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        ;
    }]
 [manager POST:(nonnull NSString *) parameters:(nullable id) headers:(nullable NSDictionary<NSString *,NSString *> *) constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        ;
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        ;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        ;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        ;
    }]
POST的请求测试1
  • 这里对应的是方法1
- (void)POSTNet {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    //创建参数
    //
    [self.AFNetWorkTestPOSTDictionary setObject:@"Viper" forKey:@"userName"];
    [self.AFNetWorkTestPOSTDictionary setObject:@"Viper333" forKey:@"passWord"];
    //发送POST请求
    [manager POST:@"https://news-at.zhihu.com/api/4/news/before/20221023" parameters:self.AFNetWorkTestPOSTDictionary headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        //responseObject是请求成功返回的相应结果,在AFN内部已经把相应结果转换为OC对象,通常是字典或者数组
        
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"POST Failed");
    }];
}
  • 这里如果只是简单的请求,和GET是一样的,方法的参数理解如下
[manager POST:(nonnull NSString *) parameters:(nullable id) headers:(nullable NSDictionary<NSString *,NSString *> *) progress:^(NSProgress * _Nonnull uploadProgress) {
        ;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        ;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        ;
    }]

 第一个参数:NSString类型的请求路径,AFN内部会自动将该路径包装为一个url并创建请求对象
 第二个参数:请求参数,以字典的方式传递,AFN内部会判断当前是POST请求还是GET请求,以选择直接拼接还是转换为NSData放到请求体中传递
 第三个参数:进度回调 此处为nil
 第四个参数:请求成功之后回调Block
 第五个参数:请求失败回调Block
POST请求测试二
  • 对应AFN提供的第二个方法
  • 我还想到了当你作为一个用户的时候不仅仅需要传输的用户的账户信息,可能也涉及到用户头像的上传,这里AFN库也提供了一种拼接数据然后上传的方法
  • 这里以一个用户的账号密码和头像混合上传为例
请求的数据拼接
  • AFN提供了三种数据拼接的方法如下

 1
  第一个参数:要上传的文件二进制数据
  第二个参数:文件参数对应的参数名称,此处为file是该台服务器规定的
  第三个参数:该文件上传到服务后以什么名称保存
  第四个参数:该文件的MIMeType类型
[formData appendPartWithFileData:data name:@"file" fileName:@"Image.png" mimeType:@"application/octet-stream"];


 2
  第一个参数:要上传的文件的URL路径
  第二个参数:文件参数对应的参数名称,此处为file是该台服务器规定的
  第三个参数:该文件上传到服务后以什么名称保存
  第四个参数:该文件的MIMeType类型
  第五个参数:错误信息,传地址

[formData appendPartWithFileURL:fileUrl name:@"file" fileName:@"Image2.png" mimeType:@"application/octet-stream" error:nil];


 3
  第一个参数:要上传的文件的URL路径
  第二个参数:文件参数对应的参数名称,此处为file
  第三个参数:错误信息
[formData appendPartWithFileURL:fileUrl name:@"file" error:nil];

POST- DEMO2
- (void)upLoad {
    //创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    //处理非文件的参数,模拟上传账号密码
    self.AFNetWorkTestPOSTDictionary = [[NSMutableDictionary alloc] init];
    [self.AFNetWorkTestPOSTDictionary setObject:@"Viper" forKey:@"userName"];
    [self.AFNetWorkTestPOSTDictionary setObject:@"Viper333" forKey:@"passWord"];
    //发送POST请求上传文件
    [manager POST:@"目标的URL" parameters:self.AFNetWorkTestPOSTDictionary headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        // 混合的数据为头像
        // 获取头像
        // 把头像转化为Data
        UIImage *image = [UIImage imageNamed:@"IMG_2400.png"];
        NSData *imageData = UIImagePNGRepresentation(image);
        //在BLOCK进行参数拼接
        //ImageUp.png是上传到服务器知乎以什么方式保存
        // 什么是MIME Type : 参考博客:https://www.cnblogs.com/jsean/articles/1610265.html
        [formData appendPartWithFileData:imageData name:@"file" fileName:@"ImageUp.png" mimeType:@"image/png"];
        //[formData appendPartWithFileURL:fileUrl name:@"file"fileName:@"Image7.png" mimeType:@"image/png" error:nil];
        //[formData appendPartWithFileURL:fileUrl name:@"file" error:nil];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        //        progress 进度回调;
        //uploadProgress.completedUnitCount:已经上传的数据大小
        //uploadProgress.totalUnitCount:数据的总大小
        NSLog(@"%f", 1.0 * uploadProgress.completedUnitCount / uploadProgress.totalUnitCount);

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"POST UP Succeed!");
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"POST UP Failed");
    }];
}
  • 注意在之前讲到的参数拼接是在constructingBodyWithBlock进行参数拼接,需要对图片进行一个DATA的转化,下面会解释
POST方法2参数理解
 [manager POST:(nonnull NSString *) parameters:(nullable id) headers:(nullable NSDictionary<NSString *,NSString *> *) constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        ;
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        ;
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        ;
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        ;
    }]
对参数的理解
 第一个参数:请求路径(NSString类型)
 第二个参数:非文件参数,以字典的方式传递
 第三个参数:constructingBodyWithBlock 在该回调中拼接文件参数
 第四个参数:progress 进度回调
 uploadProgress.completedUnitCount:已经上传的数据大小
 uploadProgress.totalUnitCount:数据的总大小
 第五个参数:success 请求成功的回调
 task:上传Task
 responseObject:服务器返回的响应体信息
 第六个参数:failure 请求失败的回调
 task:上传Task
 error:错误信息

POST方法2的注意

头像对于DATA的转换
  • 在学习第二种POST方法的过程中有几个需要说明的点
  • 如何把头像转化为DATA:
    • 获取图像
    • 把头像转化为DATA
 UIImage *image = [UIImage imageNamed:@"IMG_2400.png"];
        NSData *imageData = UIImagePNGRepresentation(image);
  • UIImagePNGRepresentation和UIImageJPEGRepresentation方法
    【iOS开发-AFNetWorking下的POST和GET】-LMLPHP

UIKIT_EXTERN  NSData * __nullable UIImagePNGRepresentation(UIImage * __nonnull image);                               // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format
-将图像返回为PNG。如果图像没有CGImageRef或位图格式无效,则可能返回nil
UIKIT_EXTERN  NSData * __nullable UIImageJPEGRepresentation(UIImage * __nonnull image, CGFloat compressionQuality);  // return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least)
- /以JPEG格式返回图像。如果图像没有CGImageRef或位图格式无效,则可能返回nil。压缩为0(最多)..1(最少)

在Block里进行拼接方法
[formData appendPartWithFileData:imageData name:@"file" fileName:@"ImageUp.png" mimeType:@"image/png"];
  • 理解:appendPartWithFileData 这里是刚才图片转换过去的Data,
  • fileName是上传到服务器以什么方式保存
MIME Type的简单认识
  • 在POST方法BLOCK里面拼接里对最后一个参数mimeType的参考,查询之后在这里简单解释一下
  • 在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有 Flash ……那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME Type,也就是该资源的媒体类型。
  • 媒体类型通常是通过 HTTP 协议,由 Web 服务器告知浏览器的,更准确地说,是通过 Content-Type 来表示的,例如:`Content-Type: text/HTML
  • 示内容是 text/HTML 类型,也就是超文本文件。为什么是“text/HTML”而不是“HTML/text”或者别的什么?MIME Type 不是个人指定的,是经过 ietf 组织协商,以 RFC 的形式作为建议的标准发布在网上的,大多数的 Web 服务器和用户代理都会支持这个规范 (顺便说一句,Email 附件的类型也是通过 MIME Type 指定的)。
    【iOS开发-AFNetWorking下的POST和GET】-LMLPHP

总结

  • 通过今天的学习初步认识到了客户端和后台的交互是如何进行的,接下来的项目里会不断的了解和深入学习交互方法
  • 写的博客如有不正确,敬请指正。
11-29 13:29