美文网首页
网络编程学习二

网络编程学习二

作者: coderhlt | 来源:发表于2018-08-02 20:07 被阅读26次

    一、请求的数据格式

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

    • 1.1 、x-www-form-urlencoded(表单)
      我们发送一个post请求时,默认数据就是以表单的形式提交的。
    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];
    
    • 2、json
    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属性进行设置。

    • 1、x-www-form-urlencoded(表单)
     AFHTTPSessionManager *sessionmanger=[[AFHTTPSessionManager alloc]init];
       sessionmanger.requestSerializer=[AFHTTPRequestSerializer serializer];
    
    • 2、json
    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(@"上传失败");
        }];
    
    

    相关文章

      网友评论

          本文标题:网络编程学习二

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