美文网首页
AFNetworking封装实践 2022-04-17 周日

AFNetworking封装实践 2022-04-17 周日

作者: 勇往直前888 | 来源:发表于2022-04-25 17:41 被阅读0次

简介

  • 目前的iOS开发,如果选择Objective-C的话,网络库基本上会选择AFNetworking

  • 网络协议一般都会上HTTPS,数据类型一般都会选择JSON

  • HTTPS的Method应该是GET和POST都有。当然,统一使用POST也是可以的,也更简单。

方案一:直接使用Http接口

既然是HTTPS,而且是JSON解析,AFNetworking也提供了顶层的POST和GET接口,封装一下很方便。

/**
 http method (1:POST,2:GET) ,
 */
typedef NS_ENUM(NSInteger,PDAHTTPMethod) {
    PDAHTTPMethodPOST = 1,
    PDAHTTPMethodGET = 2,
};

+ (void)networkWithMethod:(PDAHTTPMethod)method
                     url:(NSString *)urlString
              parameters:(nullable NSDictionary *)parameters
                 headers:(nullable NSDictionary <NSString *, NSString *> *)headers
                 success:(nullable void(^)(id _Nullable response))success
                 failure:(nullable void(^)(NSError * _Nullable error))failure {
   
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:NSJSONWritingPrettyPrinted];
    manager.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingMutableContainers];
    
    
    if (method == PDAHTTPMethodPOST) {
        [manager POST:urlString parameters:parameters headers:headers progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            if (success != nil) {
                success(responseObject);
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            if (failure != nil) {
                failure(error);
            }
        }];
    }
    
    if (method == PDAHTTPMethodGET) {
        [manager GET:urlString parameters:parameters headers:headers progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            if (success != nil) {
                success(responseObject);
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            if (failure != nil) {
                failure(error);
            }
        }];
    }
}
  • 这样封装非常简介,就是把不需要的process参数给抛弃了。success和failure参数简化了。

  • 大多数情况是没有问题。JSON解析的事情也不需要考虑。

  • 但是有时候会报错unacceptable content-type: text/plain,这个是AFNetworking本身的问题,网上也有类似的文章。
    iOS 数据请求 unacceptable content-type: text/plain

  • 按照上面文章的说法,需要修改AFNetworking源代码,这个违背了使用第三方库的基本原则。所以不是很好。考虑使用更底层的接口进行封装。

方案二:封装NSURLSessionDataTask接口

  • 不管是POST还是GET,都是一种DataTask;

  • 一些顶层参数,比如method,url之类的,都在request中配置;

  • 有些需求,比如参数加解密,有时候也需要自定义。用太顶层的接口就不大方便。

// 包装dataTaskWithRequest
+ (void)HTTTPWithMethod:(PDAHTTPMethod)method
                    url:(NSString *)urlString
             parameters:(nullable NSDictionary *)parameters
                headers:(nullable NSDictionary <NSString *, NSString *> *)headers
                success:(nullable void(^)(id _Nullable response))success
                failure:(nullable void(^)(NSError * _Nullable error))failure {
    // url
    NSURL *url = nil;
    if (method == PDAHTTPMethodPOST) {
        url = [NSURL URLWithString:urlString];
    }
    if (method == PDAHTTPMethodGET) {
        // get请求拼接参数
        NSMutableString *urlWithQury = [NSMutableString stringWithString:urlString];
        if ((parameters != nil) && (parameters.count > 0)) {
            [urlWithQury appendString:@"?"];
            NSArray *keys = parameters.allKeys;
            for (NSInteger i = 0; i < keys.count; i++) {
                NSString *keyAndValue = [NSString stringWithFormat:@"%@=%@", keys[i], [parameters objectForKey:keys[i]]];
                [urlWithQury appendString:keyAndValue];
                if (i != (parameters.count - 1)){
                    [urlWithQury appendString:@"&"];
                }
            }
        }
        url = [NSURL URLWithString:[urlWithQury copy]];
    }
    
    // request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    // method
    if (method == PDAHTTPMethodPOST) {
        [request setHTTPMethod:@"POST"];
    }
    if (method == PDAHTTPMethodGET) {
        [request setHTTPMethod:@"GET"];
    }
    
    // body 只有POST才需要设置body
    if ((parameters != nil) && (parameters.count > 0) && (method == PDAHTTPMethodPOST)) {
        NSData *jsonData = [PDAJSON dictionaryToJsonData:parameters];
        if (jsonData != nil) {
            [request setHTTPBody:jsonData];
        }
    }
    
    // headers
    if ((headers != nil) && (headers.count > 0)) {
        [headers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
            [request setValue:obj forHTTPHeaderField:key];
        }];
    }
    
    // 顶层的POST,GET接口在JSON转换的过程中有问题,所以用更底层的dataTask接口;关键是自己组NSURLRequest,避开AFNetworking本身的坑
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; // 没有baseURL,在设置securityPolicy的时候会崩溃
    
    // 执行dataTask
    NSURLSessionDataTask *task = [manager dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        if (error == nil) {
            if (success != nil) {
                success(responseObject);
            }
        } else {
            if (failure != nil) {
                failure(error);
            }
        }
    }];
    
    // 启动任务
    [task resume];
}
  • 这种方式虽然麻烦了一点,但是胜在稳定可靠,没有明显的坑。

  • AFNetworking本身提供的JSON解析并不怎么样,还不如直接使用系统API,高效又简洁。

  • POST方式的body参数,有时候还是需要加解密的。用这种方式就可以操作了。

相关文章

网友评论

      本文标题:AFNetworking封装实践 2022-04-17 周日

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