美文网首页
iOS 封装AFNetworking

iOS 封装AFNetworking

作者: 秋燕归 | 来源:发表于2024-06-23 14:39 被阅读0次

1.请求配置类

//
//  SFRequestConfig.h
//  template
//
//  Created by shefeng on 2024/6/20.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SFRequestConfig : NSObject

/**
 *  是否允许无效的证书
 */
@property (assign, nonatomic) BOOL allowInvalidCertificates;

/**
 *  超时时间
 */
@property (assign, nonatomic) NSInteger timeoutInterval;

/**
 *  是否允许无效的证书
 */
@property (assign, nonatomic) BOOL validatesDomainName;

/**
 *  可接收的ContentType类型
 */
@property (strong, nonatomic) NSSet <NSString *> *acceptableContentTypes;


/**
 *  单例
 */
+ (instancetype)sharedConfig;

@end

NS_ASSUME_NONNULL_END

//
//  SFRequestConfig.m
//  template
//
//  Created by shefeng on 2024/6/20.
//

#import "SFRequestConfig.h"

@implementation SFRequestConfig

+ (instancetype)sharedConfig{
    static dispatch_once_t onceToken;
    static SFRequestConfig *instance;
    dispatch_once(&onceToken, ^{
        instance = [[SFRequestConfig alloc] init];
    });
    return instance;
}

- (NSSet<NSString *> *)acceptableContentTypes{
    if (_acceptableContentTypes == nil) {
        _acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"image/jpeg",@"image/png",@"text/plain",@"application/json",nil];
    }
    return _acceptableContentTypes;
}

@end

2.响应配置类

//
//  SFResponseConfig.h
//  template
//
//  Created by shefeng on 2024/6/24.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface SFResponseConfig : NSObject

/**
 *  code的key
 */
@property (strong, nonatomic) NSString *codeKey;

/**
 *  data的key
 */
@property (strong, nonatomic) NSString *dataKey;

/**
 *  message的key
 */
@property (strong, nonatomic) NSString *messageKey;

/**
 *  成功的状态码
 */
@property (strong, nonatomic) NSNumber *successedCode;

/**
 *  失败的状态码
 */
@property (strong, nonatomic) NSNumber *failedCode;

/**
 *  默认的错误提示语
 */
@property (strong, nonatomic) NSString *defaultMessageValue;

/**
 *  单例
 */
+ (instancetype)sharedConfig;

@end

NS_ASSUME_NONNULL_END

//
//  SFResponseConfig.m
//  template
//
//  Created by shefeng on 2024/6/24.
//

#import "SFResponseConfig.h"

#define ResponseCodeDefaultKey @"code"
#define ResponseDataDefaultKey @"data"
#define ResponseMessageDefaultKey @"message"
#define ResponseCodeSuccessedDefaultValue @0
#define ResponseCodeFailedDefaultValue @500
#define ResponseMessageDefaultValue @"请求失败"

@implementation SFResponseConfig

+ (instancetype)sharedConfig{
    static dispatch_once_t onceToken;
    static SFResponseConfig *instance;
    dispatch_once(&onceToken, ^{
        instance = [[SFResponseConfig alloc] init];
    });
    return instance;
}

- (NSString *)codeKey{
    if (_codeKey == nil || [@"" isEqualToString:_codeKey]) {
        return ResponseCodeDefaultKey;
    }
    return _codeKey;
}

- (NSString *)dataKey{
    if (_dataKey == nil || [@"" isEqualToString:_dataKey]) {
        return ResponseDataDefaultKey;
    }
    return _dataKey;
}

- (NSString *)messageKey{
    if (_messageKey == nil || [@"" isEqualToString:_messageKey]) {
        return ResponseMessageDefaultKey;
    }
    return _messageKey;
}

- (NSNumber *)successedCode{
    if (_successedCode == nil) {
        return ResponseCodeSuccessedDefaultValue;
    }
    return _successedCode;
}

- (NSNumber *)failedCode{
    if (_failedCode == nil) {
        return ResponseCodeFailedDefaultValue;
    }
    return _failedCode;
}

- (NSString *)defaultMessageValue{
    if (_defaultMessageValue == nil || [@"" isEqualToString:_defaultMessageValue]) {
        return ResponseMessageDefaultValue;
    }
    return _defaultMessageValue;
}

@end

3.网络请求基类

//
//  SFBaseRequest.h
//  template
//
//  Created by shefeng on 2024/6/20.
//

#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSInteger, SFContentType){
    ApplicationJson,
    ApplicationXWwwFormUrlencoded,
    MultipartFormData 
};

@interface SFBaseRequest : NSObject

+ (AFHTTPSessionManager *)sharedManager;

/**
 *  GET请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数
 *  @param completionBlock 完成的block
 */
+ (void)GET:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;

/**
 *  POST请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数
 *  @param completionBlock 完成的block
 */
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;

/**
 *  POST请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数  
 *  @param contentType 请求Content-Type
 *  @param completionBlock 完成的block
 */
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers contentType:(SFContentType)contentType completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock;

@end

NS_ASSUME_NONNULL_END
//
//  SFBaseRequest.m
//  template
//
//  Created by shefeng on 2024/6/20.
//

#import "SFBaseRequest.h"
#import <MJExtension/MJExtension.h>
#import "SFRequestConfig.h"
#import "SFResponseConfig.h"

#define ResponseFailedDefaultValue @{[SFResponseConfig sharedConfig].codeKey:[SFResponseConfig sharedConfig].failedCode,[SFResponseConfig sharedConfig].messageKey:[SFResponseConfig sharedConfig].defaultMessageValue}

@implementation SFBaseRequest

+ (AFHTTPSessionManager *)sharedManager {
    static AFHTTPSessionManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [AFHTTPSessionManager manager];
        
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy defaultPolicy];
        // 客户端是否信任非法证书
        securityPolicy.allowInvalidCertificates = [SFRequestConfig sharedConfig].allowInvalidCertificates;
        // 是否在证书域字段中验证域名
        securityPolicy.validatesDomainName = [SFRequestConfig sharedConfig].validatesDomainName;
        instance.securityPolicy = securityPolicy;
        instance.requestSerializer.timeoutInterval = [SFRequestConfig sharedConfig].timeoutInterval;
        instance.responseSerializer.acceptableContentTypes = [SFRequestConfig sharedConfig].acceptableContentTypes;
    });
    return instance;
}

/**
 *  GET请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数
 *  @param completionBlock 完成的block
 */
+ (void)GET:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
    [[SFBaseRequest sharedManager] GET:urlString parameters:params headers:headers progress:^(NSProgress * _Nonnull downloadProgress) {
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
    }];
}

/**
 *  POST请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数
 *  @param completionBlock 完成的block
 */
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
    [self POST:urlString params:params headers:headers contentType:ApplicationXWwwFormUrlencoded completionBlock:completionBlock];
}

/**
 *  POST请求
 *
 *  @param urlString 请求url
 *  @param params 请求参数
 *  @param headers header参数
 *  @param contentType 请求Content-Type
 *  @param completionBlock 完成的block
 */
+ (void)POST:(NSString *)urlString params:(NSDictionary *)params headers:(NSDictionary *)headers contentType:(SFContentType)contentType completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
    if (contentType == ApplicationXWwwFormUrlencoded) {
        [[self sharedManager].requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        
        [[SFBaseRequest sharedManager] POST:urlString parameters:params headers:headers progress:^(NSProgress * _Nonnull uploadProgress) {
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
        }];
    }else if (contentType == ApplicationJson) {
        [[self sharedManager].requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
        
        NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:urlString parameters:params error:nil];

        [request setValue:@"application/json"forHTTPHeaderField:@"Content-Type"];
        
        if(headers != nil && headers.allKeys.count != 0){
            for (NSString *key in headers.allKeys) {
                NSString *value = [headers objectForKey:key];
                [request addValue:value forHTTPHeaderField:key];
            }
        }

        NSData *body = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];

        [request setHTTPBody:body];
        
        [[[SFBaseRequest sharedManager] dataTaskWithRequest:request uploadProgress:^(NSProgress * _Nonnull uploadProgress) {
                    
        } downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
            
        } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
            if (!error) {
                [self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
            }else{
                [self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
            }
        }] resume];
    }else if (contentType == MultipartFormData) {
        [[self sharedManager].requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
        
        [[SFBaseRequest sharedManager] POST:urlString parameters:params headers:headers constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
            NSArray *keyArray = [params allKeys];
            
            for (NSString *key in keyArray) {
                id value = params[key];
                if ([value isKindOfClass:[NSString class]]) {
                   [formData appendPartWithFormData:[value dataUsingEncoding:NSUTF8StringEncoding] name:key];
                }else if ([value isKindOfClass:[NSMutableArray class]]) {
                    [formData appendPartWithFormData:[NSKeyedArchiver archivedDataWithRootObject:value requiringSecureCoding:YES error:nil] name:key];
                }else if ([value isKindOfClass:[NSArray class]]) {
                    [formData appendPartWithFormData:[NSKeyedArchiver archivedDataWithRootObject:value requiringSecureCoding:YES error:nil] name:key];
                }
                
            }
        } progress:^(NSProgress * _Nonnull uploadProgress) {
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self handleSuccess:urlString params:params responseObject:responseObject completionBlock:completionBlock];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [self handleError:urlString params:params errMsg:error.localizedDescription completionBlock:completionBlock];
        }];
    }
}

/**
 *  处理错误响应
 *
 *  @param url 请求地址
 *  @param params 请求参数
 *  @param errMsg 错误信息
 *  @param completionBlock 完成的Block
 */
+ (void)handleError:(NSString *)url params:(NSDictionary *)params errMsg:(NSString *)errMsg completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
    [self printLog:url params:params info:errMsg];
    completionBlock([SFResponseConfig sharedConfig].failedCode.integerValue,nil,errMsg);
}

#pragma mark - private
/**
 *  处理成功响应
 *
 *  @param url 请求地址
 *  @param params 请求参数
 *  @param responseObject 响应数据
 *  @param completionBlock 完成的Block
 */
+ (void)handleSuccess:(NSString *)url params:(NSDictionary *)params responseObject:(id)responseObject completionBlock:(void(^)(NSInteger code,id data,NSString *message))completionBlock{
    if(responseObject == nil){
        [self handleError:url params:params errMsg:@"请求无响应" completionBlock:completionBlock];
    }else {
        if ([responseObject isKindOfClass:[NSDictionary class]]) {
            NSDictionary *responseDict = (NSDictionary *)responseObject;
            if ([responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].codeKey] 
                && [responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].messageKey]
                && [responseDict.allKeys containsObject:[SFResponseConfig sharedConfig].dataKey]) {
                NSInteger code = [[responseDict objectForKey:[SFResponseConfig sharedConfig].codeKey] integerValue];
                id data = [responseDict objectForKey:[SFResponseConfig sharedConfig].dataKey];
                NSString *message = [responseDict objectForKey:[SFResponseConfig sharedConfig].messageKey];
                [self printLog:url params:params info:[responseDict mj_JSONString]];
                completionBlock(code,data,message);
            }else{
                [self handleError:url params:params errMsg:@"返回数据格式不正确" completionBlock:completionBlock];
            }
        }else{
            [self handleError:url params:params errMsg:@"返回数据格式不正确" completionBlock:completionBlock];
        }
    }
}

/**
 *  打印log
 *
 *  @param url 请求地址
 *  @param params 请求参数
 *  @param info 响应信息
 */
+ (void)printLog:(NSString *)url params:(NSDictionary *)params info:(NSString *)info{
#ifdef DEBUG
    NSString *urlInfo = [NSString stringWithFormat:@"请求地址:%@",url];
    NSString *paramInfo = [NSString stringWithFormat:@"请求参数:%@",(params == nil ? @"" : [params mj_JSONString])];
    NSString *responseInfo = [NSString stringWithFormat:@"请求响应:%@",info];
    
    NSInteger maxLength = urlInfo.length;
    
    if (paramInfo.length > maxLength) {
        maxLength = paramInfo.length;
    }
    
    if (responseInfo.length > maxLength) {
        maxLength = responseInfo.length;
    }
    
    NSLog(@"%@",[self buildLogString:maxLength info:nil]);
    NSLog(@"%@",[self buildLogString:maxLength info:urlInfo]);
    NSLog(@"%@",[self buildLogString:maxLength info:paramInfo]);
    NSLog(@"%@",[self buildLogString:maxLength info:responseInfo]);
    NSLog(@"%@",[self buildLogString:maxLength info:nil]);
#endif
}

/**
 *  构建打印信息
 *
 *  @param maxLength 最大长度
 *  @param info 信息
 *
 */
+ (NSString *)buildLogString:(NSInteger)maxLength info:(NSString *)info{
    //非第一行和最后一行的左侧*数量
    NSInteger leftStarLength = 0;
    //非第一行和最后一行的左侧*后的空格数量
    NSInteger leftSpaceLength = 0;
    
    //实际最大长度
    maxLength += (leftStarLength + leftSpaceLength) * 2;
    
    NSMutableString *mutableStr = [[NSMutableString alloc] init];
    
    if(info == nil){
        for (int i = 0; i < maxLength; i++) {
            [mutableStr appendString:@"="];
        }
    }else{
        for (int i = 0; i < leftStarLength; i++) {
            [mutableStr appendString:@""];
        }
        
        for (int i = 0; i < leftSpaceLength; i++) {
            [mutableStr appendString:@""];
        }
        
        [mutableStr appendString:info];
        
        NSInteger rightSpaceLength = maxLength - leftStarLength - leftSpaceLength - info.length - leftStarLength;
        
        for (int i = 0; i < rightSpaceLength; i++) {
            [mutableStr appendString:@""];
        }
        
        for (int i = 0; i < leftStarLength; i++) {
            [mutableStr appendString:@""];
        }
    }
    
    return mutableStr;
}

@end

4.Java后台相关代码


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TestObj {

    private String name;
    private String address;
}

package com.geenju.bcard.modules.app.controller;

import com.geenju.bcard.common.api.CommonResult;
import com.geenju.bcard.modules.app.dto.TestObj;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/api/test")
public class TestController {

    @RequestMapping(value = "/get", method = RequestMethod.GET)
    @ResponseBody
    public CommonResult get(@RequestParam(value = "argsA") String argsA) {
        log.info("get - argsA=" + argsA);
        return CommonResult.success("");
    }

    @RequestMapping(value = "/postFormData", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult postFormData(@RequestParam(value = "argsA") String argsA) {
        log.info("postFormData - argsA=" + argsA);
        return CommonResult.success("");
    }

    @RequestMapping(value = "/postXWwwFormUrlencoded", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult postXWwwFormUrlencoded(@RequestParam(value = "argsA") String argsA) {
        log.info("postXWwwFormUrlencoded - argsA=" + argsA);
        return CommonResult.success("");
    }

    @RequestMapping(value = "/postJson", method = RequestMethod.POST)
    @ResponseBody
    public CommonResult postJson(@RequestBody TestObj testObj) {
        log.info("postJson - testObj.name=" + testObj.getName() + " testObj.address=" + testObj.getAddress());
        return CommonResult.success("");
    }
}

5.使用

配置相关参数

[SFRequestConfig sharedConfig].timeoutInterval = 30;
[SFRequestConfig sharedConfig].allowInvalidCertificates = YES;
[SFRequestConfig sharedConfig].validatesDomainName = NO;
[SFRequestConfig sharedConfig].acceptableContentTypes = [NSSet setWithObjects:@"text/html",@"image/jpeg",@"image/png",@"text/plain",@"application/json",nil];
    
[SFResponseConfig sharedConfig].codeKey = @"code";
[SFResponseConfig sharedConfig].dataKey = @"data";
[SFResponseConfig sharedConfig].messageKey = @"msg";
[SFResponseConfig sharedConfig].successedCode = @0;
[SFResponseConfig sharedConfig].failedCode = @500;
[SFResponseConfig sharedConfig].defaultMessageValue = @"请求失败";

调用

[self testGet:@"value of args"];
[self testPostFormData:@"value of args"];
[self testPostFormUrlencoded:@"value of args"];
[self testPostJson:@"hello" address:@"world"];

- (void)testGet:(NSString *)argsA{
    [SFBaseRequest GET:@"http://192.168.0.121:9000/api/test/get" params:@{@"argsA":argsA} headers:@{} completionBlock:^(NSInteger code, id  _Nonnull data, NSString * _Nonnull message) {
   
    }];
}

- (void)testPostFormData:(NSString *)argsA{
    [SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postFormData" params:@{@"argsA":argsA} headers:@{} completionBlock:^(NSInteger code, id  _Nonnull data, NSString * _Nonnull message) {
   
    }];
}

- (void)testPostFormUrlencoded:(NSString *)argsA{
    [SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postXWwwFormUrlencoded" params:@{@"argsA":argsA} headers:@{} contentType:ApplicationXWwwFormUrlencoded completionBlock:^(NSInteger code, id  _Nonnull data, NSString * _Nonnull message) {
 
    }];
}

- (void)testPostJson:(NSString *)name address:(NSString *)address{
    [SFBaseRequest POST:@"http://192.168.0.121:9000/api/test/postJson" params:@{@"name":name,@"address":address} headers:@{} contentType:ApplicationJson completionBlock:^(NSInteger code, id  _Nonnull data, NSString * _Nonnull message) {

    }];
}

6.调试

==============================================================
请求地址:http://192.168.0.121:9000/api/test/postXWwwFormUrlencoded
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
==============================================================
===========================================
请求地址:http://192.168.0.121:9000/api/test/get
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
===========================================
================================================
请求地址:http://192.168.0.121:9000/api/test/postJson
请求参数:{"name":"hello","address":"world"}
请求响应:{"msg":"操作成功","data":"","code":200}
================================================
====================================================
请求地址:http://192.168.0.121:9000/api/test/postFormData
请求参数:{"argsA":"value of args"}
请求响应:{"msg":"操作成功","data":"","code":200}
====================================================

相关文章

网友评论

      本文标题:iOS 封装AFNetworking

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