网络编程学习二

2018-08-02  本文已影响26人  coderhlt

一、请求的数据格式

在网络数据传输过程中,服务器是不支持ios对象的,ios端是不能直接提交字符串、字典等,需要在提交前把数据转换为二进制数据。服务器在接收数据后需要对二进制数据进行解析,但服务器有必要知道这些数据格式是json,还是图片,还是音视频呢?这就需要客户端在请求头Content-Type中告知服务器。
在开发中一般请求的数据格式要么是表单,要么是json 。

POST
header:
Content-Type: "x-www-form-urlencoded"
body:
key1=value1&key2=value2
/*key1=value1
key2=value2
*/
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://apis.juhe.cn/catering/querybycity"]];
    request.HTTPMethod=@"POST";

   //设置请求数据类型
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

     NSData*requestdata=[@"key=9e0169318d2bdaa82abf75f3c0e7d173&city=上海"dataUsingEncoding:NSUTF8StringEncoding];
    request.HTTPBody=requestdata;
    NSURLSession *session=[NSURLSession sharedSession];
    NSURLSessionTask *sessiontask=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

  }];
   [sessiontask resume];

1.2 、x-www-form-urlencoded(表单)

header:
Content-Type: "x-www-form-urlencoded"
body:
key1=value1
key2={"key3":value3, "key4": value4}

注意这里还是一个表单,表单里面嵌套了一个JSON字符串

    NSURL *url =[NSURL URLWithString:@"http://49.4.5.233:9111/api/getService"];
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod=@"POST";
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    

    //转换为jsonstring
    NSDictionary *dic=@{
                        @"nmae":@"zhangsan",
                        @"jobnumber":@"001"
                        };
    
    NSData *jsondata=[NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
    NSString  *jsonstring=[[NSString alloc]initWithData:jsondata encoding:NSUTF8StringEncoding];

//josnstring拼接到表单里
    NSString *paramas=[NSString   stringWithFormat:@"key=9e0169318d2bdaa82abf75f3c0e7d173&message=%@",jsonstring];
   NSData*requestdata=[paramas  dataUsingEncoding:NSUTF8StringEncoding];
   request.HTTPBody=requestdata;
   NSURLSession *session=[NSURLSession sharedSession];
    NSURLSessionTask *sessiontask=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

  }];
   [sessiontask resume];
header:
Content-Type: "application/json"

body:
{
    "key1": value1,
    "key2": value2
}
    NSURL *url =[NSURL URLWithString:@"http://nweeeeeikeji.com/jinyunfuni/product/homeVideoRecommend"];
    NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];//设置请求数据类型
    NSDictionary *dic=@{
                        @"imageType":@"homebanner",
                        @"loginO":@"1"
                        };
    NSData *jsondata=[NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:nil];
    request.HTTPMethod=@"POST";
    request.HTTPBody=jsondata;
    NSURLSession *session =[NSURLSession sharedSession];
    
    NSURLSessionDataTask *sessiontask=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

    }];
    
    [sessiontask resume];
}

二、AFN设置请求数据格式

AFN内部实现

@implementation AFJSONRequestSerializer
[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]

@implementation AFHTTPRequestSerializer
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]

通过以上可以知道,AFN设置请求数据格式可以方便的通过AFHTTPSessionManager的requestSerializer属性进行设置。

 AFHTTPSessionManager *sessionmanger=[[AFHTTPSessionManager alloc]init];
   sessionmanger.requestSerializer=[AFHTTPRequestSerializer serializer];
AFHTTPSessionManager *sessionmanger=[[AFHTTPSessionManager alloc]init];
    sessionmanger.requestSerializer=[AFJSONRequestSerializer serializer]

三、AFN使用报错探究

源码:

- (void)viewDidLoad {
    [super viewDidLoad];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:@"https://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {  
       NSLog(@"%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

运行之后:请求失败--Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html" 。

分析:报错原因就是响应不接受 text/html类型.也就是afn序列化时不支持 text/html类型,我们需要手动设置一下manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"text/html"].

修改后:

- (void)viewDidLoad {
    [super viewDidLoad];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    //对于服务器返回数据,告诉afn在序列化时支持text/html类型
    manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"text/html",@"application/json", nil];
    
    [manager POST:@"https://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSLog(@"%@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

运行之后: 请求失败--Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}

分析:对于服务器返回的数据,afn默认会把它当作json来处理。很显然,我们请求的百度首页 返回的并不是一个json文本,而是一个html网页,但是AFNetworking并不知道,它坚信请求的结果就是一个json文本!然后固执地以json的形式去解析,显然没办法把一个网页解析成一个字典或者数组,所以产生了上述错误.因此,我们需要手动设置 manager.responseSerializer=[AFHTTPResponseSerializer serializer]告诉afn以二进制的形式对它进行解析就好了。

纠正后:

- (void)viewDidLoad {
    [super viewDidLoad];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    
    //对于服务器返回数据,告诉afn在序列化时支持text/html类型
    manager.responseSerializer.acceptableContentTypes=[NSSet setWithObjects:@"text/html",@"application/json", nil];
    
    //对于服务器返回数据,以二进制的形式进行解析(如果返回的数据既不是xml也不是json那么应该修改成这样)
    manager.responseSerializer=[AFHTTPResponseSerializer serializer];
    
    [manager POST:@"https://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSLog(@"%@",responseObject);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

四、图片上传

multipart/form-data 用于文件上传领域,在iOS开发中很多时候需要会涉及到上传图片等服务器交互的操作,基本上全部都会使用Multipart/form-data的请求方式来完成上传.需要我们去严格按照规范的格式来组装请求体 , 每一个换行每一个空格都是不可忽略的 ,AFN已经很好的为我们封装了。

    AFHTTPSessionManager *manger = [AFHTTPSessionManager manager];
    [manger POST:@"http://120.25.226.186:32812/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSData *data=[NSData dataWithContentsOfFile:@"/Users/reitaketachibana/Desktop/屏幕快照 2018-03-27 下午3.38.04.png"];
        [formData appendPartWithFileData:data name:@"file1" fileName:@"屏幕快照 2018-03-27 下午3.38.04.png"
                               mimeType:@"image/png"];
        
    } progress:^(NSProgress * _Nonnull uploadProgress) {
      NSLog(@"上传进度");
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        
        NSLog(@"上传成功%@",task.currentRequest.allHTTPHeaderFields);
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"上传失败");
    }];

上一篇 下一篇

猜你喜欢

热点阅读