直接上代码
.h文件
//
// HWNetworking.h
// SpeakerNetworkConfig
//
// Created by 陈帆 on 2019/10/23.
// Copyright © 2019 wenming liu. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
请求数据类型
- RequestSerializerJSON: JSON字符串("{\"a\":\"value1\",\"b\":\"value2\"}")
- RequestSerializerNormal: 普通的&符号链接("a=value1&b=value2")
*/
typedef NS_ENUM(NSUInteger, RequestSerializerType){
RequestSerializerJSON = 0,
RequestSerializerNormal
};
@class HWSecurityPolicy;
/**
请求成功返回block
@param response 响应对象
@param responseObject 数据对象
@param error 错误对象
*/
typedef void (^HttpSuccessCallback)(NSURLResponse * _Nullable response, id _Nullable responseObject, NSError * _Nullable error);
/**
请求失败返回block
@param error 错误对象
*/
typedef void (^HttpFailCallback)(NSError * _Nullable error);
@interface HWNetworking : NSObject
/**
超时时间 单位:s
*/
@property (assign, nonatomic) NSTimeInterval time;
/**
请求header
*/
@property (strong, nonatomic) NSMutableDictionary *headerDict;
/**
证书
*/
@property (strong, nonatomic) NSSet <NSData *> *cersData;
/**
请求类型
*/
@property (assign, nonatomic) RequestSerializerType serializerType;
/**
单例
@return 单例对象
*/
+ (instancetype)sharedInstance;
/**
get http请求
@param url url
@param paramsDict 参数列表
@param successCallback 成功返回callback
@param failureCallback 失败返回callback
*/
- (void)httpGetWithUrl:(NSString *)url params:(NSDictionary *)paramsDict success:(HttpSuccessCallback)successCallback failure:(HttpFailCallback)failureCallback;
/**
post http请求
@param url url
@param paramsDict 参数列表
@param successCallback 成功返回callback
@param failureCallback 失败返回callback
*/
- (void)httpPostWithUrl:(NSString *)url params:(NSDictionary *)paramsDict success:(HttpSuccessCallback)successCallback failure:(HttpFailCallback)failureCallback;
/**
iOS 原生数据请求
@param url url
@param dic 参数
@param method 请求方法
@param success 成功
@param failure 失败
*/
- (void)httpRequestWithUrl:(NSString *)url body:(NSDictionary *)dic header:(NSDictionary *)header method:(NSString *)method timeout:(NSTimeInterval)time success:(HttpSuccessCallback)success failure:(HttpFailCallback)failure;
# pragma static method
@end
NS_ASSUME_NONNULL_END
.m文件
#import "HWNetworking.h"
#import <UIKit/UIKit.h>
@interface HWNetworking() <NSURLSessionTaskDelegate>
@end
@implementation HWNetworking
- (instancetype)init {
self = [super init];
if (self) {
// init
self.time = 15.0f;
self.serializerType = RequestSerializerJSON;
}
return self;
}
+ (instancetype)sharedInstance {
static HWNetworking *instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[HWNetworking alloc] init];
});
return instance;
}
/**
get http请求
@param url url
@param paramsDict 参数列表
@param successCallback 成功返回callback
@param failureCallback 失败返回callback
*/
- (void)httpGetWithUrl:(NSString *)url params:(NSDictionary *)paramsDict success:(HttpSuccessCallback)successCallback failure:(HttpFailCallback)failureCallback {
[self httpRequestWithUrl:url body:paramsDict header:self.headerDict method:@"GET" timeout:self.time success:successCallback failure:failureCallback];
}
/**
post http请求
@param url url
@param paramsDict 参数列表
@param successCallback 成功返回callback
@param failureCallback 失败返回callback
*/
- (void)httpPostWithUrl:(NSString *)url params:(NSDictionary *)paramsDict success:(HttpSuccessCallback)successCallback failure:(HttpFailCallback)failureCallback {
[self httpRequestWithUrl:url body:paramsDict header:self.headerDict method:@"POST" timeout:self.time success:successCallback failure:failureCallback];
}
/**
iOS 原生数据请求
@param url url
@param dic 参数
@param method 请求方法
@param success 成功
@param failure 失败
*/
- (void)httpRequestWithUrl:(NSString *)url body:(NSDictionary *)dic header:(NSDictionary *)header method:(NSString *)method timeout:(NSTimeInterval)time success:(HttpSuccessCallback)success failure:(HttpFailCallback)failure {
// 1、创建URL
NSString *URLString = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *urls = [NSURL URLWithString:URLString];
// 2、创建请求对象
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:urls];
[request setHTTPMethod:method];
if (dic) {
// 3、设置body
NSData *bodyData = [self dealWithParam:dic];
if (bodyData) {
[request setHTTPBody:bodyData];
}
}
// 4. 设置header
if (header) {
[request setAllHTTPHeaderFields:header];
// 添加额外header
[request setValue:@"zh-Hans-CN;q=1, en-CN;q=0.9" forHTTPHeaderField:@"Accept-Language"];
[request setValue:[NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]] forHTTPHeaderField:@"User-Agent"];
}
// 5. 设置timeout value
[request setTimeoutInterval:time];
// 6. set mode
[request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
// 创建会话
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 创建数据请求任务
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *_Nullable data,NSURLResponse * _Nullable response,NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
failure(error);
} else {
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if (dic) {
success(response, dic, nil);
} else {
failure(error);
}
}
});
}];
// 启动任务
[task resume];
}
- (void)dealloc
{
// 回收处理
}
#pragma mark - NSURLSessionDelegate
#pragma mark didReceiveChallenge
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler
{
if ([[[challenge protectionSpace] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
do {
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
NSCAssert(serverTrust != nil, @"serverTrust is nil");
if(nil == serverTrust)
break; /* failed */
/**
* 导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA),请替换掉你的证书名称
*/
if (!self.cersData) {
break;
}
NSMutableArray *caArray = [NSMutableArray array];
for (NSData *cerData in self.cersData) {
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)cerData);
NSCAssert(caRef != nil, @"caRef is nil");
if(nil == caRef)
break; /* failed */
//可以添加多张证书
[caArray addObject:(__bridge id)(caRef)];
}
NSCAssert(caArray != nil, @"caArray is nil");
if(nil == caArray)
break; /* failed */
//将读取的证书设置为服务端帧数的根证书
OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
if(!(errSecSuccess == status))
break; /* failed */
SecTrustResultType result = -1;
//通过本地导入的证书来验证服务器的证书是否可信
status = SecTrustEvaluate(serverTrust, &result);
if(!(errSecSuccess == status))
break; /* failed */
BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);
/* kSecTrustResultUnspecified and kSecTrustResultProceed are success */
if(! allowConnect)
{
break; /* failed */
}
#if 0
/* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success */
/* since the user will likely tap-through to see the dancing bunnies */
if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)
break; /* failed to trust cert (good in this case) */
#endif
// The only good exit point
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
return [[challenge sender] useCredential: credential forAuthenticationChallenge: challenge];
}
while(0);
}
// Bad dog
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,credential);
return [[challenge sender] cancelAuthenticationChallenge: challenge];
}
#pragma mark static method
// 处理字典参数
- (NSData *)dealWithParam:(NSDictionary *)param {
if (self.serializerType == RequestSerializerJSON) {
return [NSJSONSerialization dataWithJSONObject:param options:NSJSONWritingPrettyPrinted error:nil];
} else {
NSArray *allkeys = [param allKeys];
NSMutableString *result = [NSMutableString string];
//"a=b&c=d"
for (NSString *key in allkeys) {
id value = param[key];
NSString *str = @"";
if ([value isKindOfClass:[NSString class]]) {
str = [NSString stringWithFormat:@"%@=%@&",key,[HWNetworking urlEncodeString:param[key]]];
} else {
str = [NSString stringWithFormat:@"%@=%@&",key, param[key]];
}
[result appendString:str];
}
[result substringWithRange:NSMakeRange(0, result.length-1)];
return [result dataUsingEncoding:NSUTF8StringEncoding];
}
}
// url encoding
+ (NSString *)urlEncodeString:(NSString *)string {
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
static NSUInteger const batchSize = 50;
NSUInteger index = 0;
NSMutableString *escaped = @"".mutableCopy;
while (index < string.length) {
NSUInteger length = MIN(string.length - index, batchSize);
NSRange range = NSMakeRange(index, length);
// To avoid breaking up character sequences such as 👴🏻👮🏽
range = [string rangeOfComposedCharacterSequencesForRange:range];
NSString *substring = [string substringWithRange:range];
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
[escaped appendString:encoded];
index += range.length;
}
return escaped;
}
@end
网友评论