最近公司项目闲下来,业余时间自己写了个请求封装类(OC / SWIFT),供大家参考,有不好的地方请大家见谅。
- tableview刷新控件cocopod集成
一、先给大家介绍一下OC VNHttpRequestManager 封装类
cocopods集成
https://github.com/guohongqi-china/VNHttpRequest
此类包含以下特点:
- 丰富的请求类型。常用请求类型,除了get、post 之外还支持 put、delete、patch、head等请求方式。
- 全面的参数提交类型。正常情况下,form 表单提交参数方式,我们大多数使用在文件交互方面;但是极少数情况下我们可能会使用到 form 表单 进行数据交互;此时如果提交方式不匹配,可能会存在接口不通或者接口通了,但是返回的数据状态不正确。
- 上传文件优化。批次上传图片,并对较大的图片做压缩优化;视频、音频也支持多批次。
- 支持断点下载文件。
- 丰富的错误信息采集。ServerResponseInfo 类采集了 http 响应码(响应码对应状态提示)、AFNet 响应码(响应码对应状态提示)、响应头信息。有些接口请求ResponseBody是不返回信息的,而是通过ResponseHeaders返回。
- 日志中的 Unicode 编码优化。某些情况,我们从后台获取的数据打印日志为Unicode编码,此类做了日志转码优化操作,使我们更能清晰的看到响应内容。
对于某些特殊的请求需要设置 请求头,或者请求超时时间(默认超时时间 10 s) 可在 + (void)requestSerializerSetting:(AFHTTPRequestSerializer *)requestSerializer;.m 文件方法中设置
.h 文件
//
// Created by guohq on 2018/6/27.
// Copyright © 2018年 guohq. All rights reserved.
//
#import
@class ServerResponseInfo;
// 请求方式类型枚举
typedef NS_ENUM(NSInteger,RequestMethod){
RequestMethod_Get = 100,
RequestMethod_Post,
RequestMethod_Put,
RequestMethod_Delete,
RequestMethod_Patch,
RequestMethod_HEAD,
};
// 请求方式类型枚举
typedef NS_ENUM(NSInteger,BodyType){
BodyType_JSON = 1000,
BodyType_FORM,
};
// 请求类型枚举
typedef NS_ENUM(NSInteger,RequestType){
RequestType_UPLOAD = 10000, //上传文件
RequestType_REQUEST //交互
};
// 文件类型
typedef NS_ENUM(NSInteger,FileType){
FileType_Video = 100000, //上传视频、音频
FileType_Image //上传图片
};
// 请求成功回调
typedef void(^resultBlock)(ServerResponseInfo * _Nullable serverInfo);
/**
* 注意:如有特殊请求头要求请在 .m文件 requestSerializerSetting 方法里面设置。
*/
@interface VNHttpRequestManager : NSObject
/**
JSON 参数
@param requestMethod 请求类型(枚举值)
@param params 请求参数
@param pathUrl 请求链接
@param result 数据回调
*/
+(void)sendJSONRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
params:(NSDictionary *_Nullable)params
complement:(resultBlock __nonnull)result;
/**
JSON 加密 参数
@param requestMethod 请求类型(枚举值)
@param requestData 加密之后的参数数据
@param pathUrl 请求链接
@param result 数据回调
*/
+(void)sendJSONRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
requestData:(NSData *_Nullable)requestData
complement:(resultBlock __nonnull)result;
/**
FormData 参数类型
@param requestMethod 请求类型(枚举值)
@param params 请求参数
@param pathUrl 请求链接
@param result 数据回调
*/
+(void)sendFORMRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
params:(NSDictionary *_Nullable)params
complement:(resultBlock __nonnull)result;
/**
批次上传文件
@param fileArray 文件路径数组 注意:fileArray 里面的文件类型要保持一致
@param bodDic 请求参数
@param path 请求链接
@param result 数据回调
@param fileType 上传文件的类型 图片 or 视/音频
*/
+ (void)uploadFileWithPath:(NSString *__nonnull)path
filePath:(NSArray *__nonnull)fileArray
parms:(NSDictionary *_Nullable)bodDic
fileType:(FileType)fileType
result:(resultBlock __nonnull)result;
/**
文件下载
@param pathUrl 下载路径
@param filePath 下载路径 可传 null
@param complement 数据回调
*/
+ (NSURLSessionDownloadTask *_Nullable)downLoadRequest:(NSString *__nonnull)pathUrl
filePath:(NSString *_Nullable)filePath
downProgress:(void (^_Nullable)(double progress))downProgress
complement:(void (^_Nullable)(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error))complement;
/**
请求管理者特殊要求头部设置(未作特殊要求,不用调用次函数,一般全局只需调用一次)
@param headerFields 下载路径
*/
+ (void)requestHeaderWidth:(NSDictionary *_Nullable)headerFields;
/**
一般请求头全局只需设置一次,不要多次设置,如果需要多次设置请求头请设置为NO;
@param result 是否需要删除请求头,不删除就会多次设置,浪费时间
*/
//+ (void)deleteHeaderSeting:(BOOL)result;
/**
开始下载
@param downloadTask 下载管理者
*/
+ (void)startResume:(NSURLSessionDownloadTask *_Nullable)downloadTask;
/**
下载暂停
@param downloadTask 下载管理者
*/
+ (void)suspend:(NSURLSessionDownloadTask *_Nullable)downloadTask;
/**
取消请求
*/
+ (void)cancleRequestWork;
/**
网络状态监听
*/
+ (void)netWorkReachability:(void(^_Nullable)(NSString * _Nullable))currentStatus;
@end
// 错误信息 详情
@interface ServerResponseInfo : NSObject
@property (nonatomic,getter=isSuccess) BOOL responeStatus; //响应是否成功
@property (nonatomic, strong) id _Nullable response; //成功响应数据
@property (nonatomic, strong) id _Nullable errorData;
@property (nonatomic, assign) NSInteger httpCode; // http 响应码
@property (nonatomic, copy) NSString * _Nullable errorMessage; // 响应提示
@property (nonatomic, copy) NSString * _Nullable httpMessage; // http 响应提示
@property (nonatomic, strong) NSDictionary * _Nullable responseHeader; // 响应header
@end
.m
//
// VNHttpRequestManager.m
// 声未识别
//
// Created by guohq on 2018/6/27.
// Copyright © 2018年 guohq. All rights reserved.
//
#import "VNHttpRequestManager.h"
#import "AFNetworking.h"
#import "VNRequestOperation.h"
static NSMutableDictionary *headerDic;
//setting request header then delete headerDic , default YES,
static BOOL setedDelete = NO;
@interface AFHttpClientManager : AFHTTPSessionManager
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (strong, nonatomic, nonnull) NSOperationQueue *requestQueue;
+(AFHttpClientManager *)sharedClient;
@end
@implementation AFHttpClientManager
static AFHttpClientManager *client = nil;
/**
* 单例
*/
+(AFHttpClientManager *)sharedClient{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
client = [AFHttpClientManager manager];
//Https setting
client.securityPolicy.allowInvalidCertificates = YES;
client.securityPolicy = [AFSecurityPolicy defaultPolicy];
client.responseSerializer = [AFHTTPResponseSerializer serializer];
client.requestQueue = [[NSOperationQueue alloc]init];
client.requestQueue.name = @"com.vn.requetQueue";
// 默认最大并发数为6
client.requestQueue.maxConcurrentOperationCount = 6;
//response data type
client.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/html", @"text/javascript",@"text/plain",@"image/gif", nil];
});
return client;
}
// 不同请求头部设置
+ (void)requestSerializerSetting:(AFHTTPRequestSerializer *)requestSerializer{
//time out 超时时间
[requestSerializer willChangeValueForKey:@"timeoutInterval"];
requestSerializer.timeoutInterval = 20.f;
[requestSerializer didChangeValueForKey:@"timeoutInterval"];
@synchronized (client.requestSerializer) {
if (headerDic.allKeys.count) {
for (NSString *key in headerDic) {
[client.requestSerializer setValue:headerDic[key] forHTTPHeaderField:key];
}
}
}
}
+ (NSMutableURLRequest *)requestData:(NSData *)data with:(NSString *)url paramType:(BodyType)type{
NSMutableURLRequest *request ;
if (type == BodyType_JSON) {
request = [[AFJSONRequestSerializer serializer] requestWithMethod:@"POST" URLString:url parameters:nil error:nil];
}else{
request = [[AFHTTPRequestSerializer serializer] requestWithMethod:@"POST" URLString:url parameters:nil error:nil];
}
// 超时设置
[request willChangeValueForKey:@"timeoutInterval"];
request.timeoutInterval= 30.0f;
[request didChangeValueForKey:@"timeoutInterval"];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
@synchronized (client.requestSerializer) {
if (headerDic.allKeys.count) {
for (NSString *key in headerDic) {
[client.requestSerializer setValue:headerDic[key] forHTTPHeaderField:key];
}
}
}
// 设置body
[request setHTTPBody:data];
return request;
}
@end
@implementation VNHttpRequestManager
//JSON 参数类型
+(void)sendJSONRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
params:(NSDictionary *_Nullable)params
complement:(resultBlock __nonnull)result{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
// json格式 请求参数
client.requestSerializer = [AFJSONRequestSerializer serializer];
[client.requestSerializer setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
typeof(client) weakClient = client;
VNRequestOperation *requestOperation = [[VNRequestOperation alloc]initOperationWithTask:^{
// 请求头设置
[AFHttpClientManager requestSerializerSetting:weakClient.requestSerializer];
[VNHttpRequestManager requestWidth:requestMethod requestManager:weakClient pathUrl:pathUrl params:params requestCount:0 complement:result];
}];
[client.requestQueue addOperation:requestOperation];
}
//JSON 参数加密类型
+(void)sendJSONRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
requestData:(NSData *_Nullable)requestData
complement:(resultBlock __nonnull)result{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
//对url 进行汉字转码 iOS 9.0
NSString *serverUrl = [pathUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
NSMutableURLRequest *request = [AFHttpClientManager requestData:requestData with:serverUrl paramType:BodyType_JSON];
// 请求头设置
[AFHttpClientManager requestSerializerSetting:client.requestSerializer];
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [client dataTaskWithRequest:[request copy] uploadProgress:^(NSProgress * _Nonnull uploadProgress) {
} downloadProgress:^(NSProgress * _Nonnull downloadProgress) {
} completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
#ifdef DEBUG
NSLog(@"URL Value=%@",serverUrl);
#endif
[VNHttpRequestManager handleFailTask:dataTask error:error complement:result];
}else{
// 服务器响应 log 数据
#ifdef DEBUG
NSLog(@"URL Value=%@",serverUrl);
#endif
[VNHttpRequestManager handleSuccessTask:dataTask responseObject:responseObject complement:result];
}
}];
}
//FORM 参数类型
+(void)sendFORMRequestWithMethod:(RequestMethod )requestMethod
pathUrl:(NSString *__nonnull)pathUrl
params:(NSDictionary *_Nullable)params
complement:(resultBlock __nonnull)result{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
// formData格式 请求参数
client.requestSerializer = [AFHTTPRequestSerializer serializer];
[client.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
// 请求头设置
typeof(client) weakClient = client;
VNRequestOperation *requestOperation = [[VNRequestOperation alloc]initOperationWithTask:^{
[AFHttpClientManager requestSerializerSetting:weakClient.requestSerializer];
[VNHttpRequestManager requestWidth:requestMethod requestManager:weakClient pathUrl:pathUrl params:params requestCount:0 complement:result];
}];
[client.requestQueue addOperation:requestOperation];
}
//上传文件
+ (void)uploadFileWithPath:(NSString *__nonnull)path
filePath:(NSArray *__nonnull)fileArray
parms:(NSDictionary *_Nullable)bodDic
fileType:(FileType)fileType
result:(resultBlock __nonnull)result{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
// json格式 请求参数
client.requestSerializer = [AFJSONRequestSerializer serializer];
[client.requestSerializer setValue:@"application/json;charset=utf-8;" forHTTPHeaderField:@"Content-Type"];
// 请求头设置
[AFHttpClientManager requestSerializerSetting:client.requestSerializer];
[VNHttpRequestManager startRequestByMethod:RequestMethod_Post
requestManager:client
requestPath:path
bodyParams:bodDic
fileType:fileType
requestType:RequestType_UPLOAD
fileArray:fileArray
complement:result];
}
+ (NSURLSessionDownloadTask *)downLoadRequest:(NSString *__nonnull)pathUrl
filePath:(NSString *_Nullable)filePath
downProgress:(void (^)(double progress))downProgress
complement:(void (^_Nullable)(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error))complement{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
// json格式 请求参数
client.requestSerializer = [AFJSONRequestSerializer serializer];
[client.requestSerializer setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
// 请求头设置
[AFHttpClientManager requestSerializerSetting:client.requestSerializer];
//请求
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:pathUrl]];
NSURLSessionDownloadTask *downTask = [client downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
downProgress(downloadProgress.completedUnitCount * 0.1 / (downloadProgress.totalUnitCount * 0.1));
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
if (filePath) {
return [NSURL fileURLWithPath:filePath];;
}
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [cachesPath stringByAppendingPathComponent:response.suggestedFilename];
return [NSURL fileURLWithPath:path];
} completionHandler:complement];
return downTask;
}
// 开始下载
+ (void)startResume:(NSURLSessionDownloadTask *_Nullable)downloadTask{
[downloadTask resume];
}
// 下载暂停
+ (void)suspend:(NSURLSessionDownloadTask *_Nullable)downloadTask{
[downloadTask suspend];
}
// 网络请求取消
+ (void)cancleRequestWork{
AFHttpClientManager *client = [AFHttpClientManager sharedClient];
[client.task cancel];
}
+ (void)requestHeaderWidth:(NSDictionary *_Nullable)headerFields{
headerDic = [headerFields mutableCopy];
}
+ (void)deleteHeaderSeting:(BOOL)result{
// setedDelete = result;
}
#pragma mark------------------------------------ 私有方法 --------------------------------------------------
// 响应重定向再次发起请求
+ (void)requestWidth:(RequestMethod)method
requestManager:(AFHttpClientManager *)manager
pathUrl:(NSString *)pathUrl
params:(NSDictionary *)params
requestCount:(NSInteger)requestCount
complement:(resultBlock)result{
__block NSInteger count = requestCount;
[VNHttpRequestManager startRequestByMethod:method
requestManager:manager
requestPath:pathUrl
bodyParams:params
fileType:0
requestType:RequestType_REQUEST
fileArray:nil
complement:^(ServerResponseInfo *serverInfo) {
//网络请求重定向
if (serverInfo.httpCode == 302 && count < 2) {
count ++;
[VNHttpRequestManager requestWidth:method requestManager:manager pathUrl:pathUrl params:params requestCount:count complement:result];
}else{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
result(serverInfo);
}];
}
}];
}
/**
服务器响应数据解析
@param requestMethod 请求类型(枚举值)
@param params 请求参数
@param pathUrl 请求链接
@param result 数据回调
@param requestType 数据交互/上传文件
@param fileArray 文件路径数组
@param fileType 上传文件的类型(视频、图片)
*/
+ (void)startRequestByMethod:(RequestMethod)requestMethod
requestManager:(AFHttpClientManager *)manager
requestPath:(NSString *)pathUrl
bodyParams:(NSDictionary *)params
fileType:(FileType)fileType
requestType:(RequestType)requestType
fileArray:(NSArray *)fileArray
complement:(resultBlock)result{
//对url 进行汉字转码 iOS 9.0
NSString *serverUrl = [pathUrl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
void (^successBlock)(NSURLSessionDataTask *,id) = ^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// 服务器响应 log 数据
#ifdef DEBUG
NSLog(@"URL Value=%@",serverUrl);
NSLog(@"Parms Value=%@",params);
#endif
[VNHttpRequestManager handleSuccessTask:task responseObject:responseObject complement:result];
};
void (^failureBlock)(NSURLSessionDataTask *,NSError *) =^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
#ifdef DEBUG
NSLog(@"URL Value=%@",serverUrl);
NSLog(@"Parms Value=%@",params);
#endif
[VNHttpRequestManager handleFailTask:task error:error complement:result];
};
switch (requestType) {
case RequestType_REQUEST:
{
[VNHttpRequestManager startRequestByMethod:requestMethod requestManager:client requestPath:serverUrl bodyParams:params successBlock:successBlock failureBlock:failureBlock];
}
break;
case RequestType_UPLOAD:
{
[VNHttpRequestManager uploadFileWithManager:client requestPath:serverUrl bodyParams:params fileArray:fileArray fileType:fileType successBlock:successBlock failureBlock:failureBlock];
}
break;
default:
break;
}
}
+ (void)handleSuccessTask:(NSURLSessionDataTask * _Nonnull )task responseObject:(id _Nullable)responseObject complement:(resultBlock)result{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
// 获取相应code值
ServerResponseInfo *infoData = [ServerResponseInfo new];
infoData.httpCode = response.statusCode;
infoData.responseHeader = [VNHttpRequestManager josnSerialization:response.allHeaderFields];
infoData.responeStatus = YES;
#ifdef DEBUG
NSLog(@"ResponseStateCode Value=%ld",(long)infoData.httpCode);
#endif
// 服务器数据解析
[self getObjectFromJSONData:responseObject complement:^(NSError *error, id jsonObject) {
NSDictionary *allHeaders = response.allHeaderFields;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:allHeaders options:NSJSONWritingPrettyPrinted
error:&error];
if (jsonObject) {
//如果接口相应数据放在响应体(body)里面,走这里。
infoData.response = jsonObject;
infoData.errorData = error;
result(infoData);
}else{
//如果接口相应数据放在响应头里面,走这里。
[self getObjectFromJSONData:jsonData complement:^(NSError *error, id jsonObject) {
infoData.response = jsonObject;
infoData.errorData = error;
result(infoData);
}];
}
}];
}
+ (void)handleFailTask:(NSURLSessionDataTask * _Nonnull )task error:(NSError * _Nonnull)error complement:(resultBlock)result{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
ServerResponseInfo *infoData = [ServerResponseInfo new];
infoData.httpCode = response.statusCode;
infoData.responseHeader = [VNHttpRequestManager josnSerialization:response.allHeaderFields];
infoData.responeStatus = NO;
#ifdef DEBUG
NSLog(@"ResponseStateCode Value=%ld",(long)infoData.httpCode);
for (id errorInfo in error.userInfo.allKeys) {
id obj = error.userInfo[errorInfo];
if ([obj isKindOfClass:NSData.class]) {
NSString *resul1t =[[ NSString alloc] initWithData:error.userInfo[errorInfo] encoding:NSUTF8StringEncoding];
obj = resul1t;
}
NSLog(@"Error %@ : %@",errorInfo, obj);
}
#endif
[self getErrorInfo:error infoData:infoData];
infoData.errorData = error;
result(infoData);
}
//发起请求
+ (void)startRequestByMethod:(RequestMethod)requestMethod
requestManager:(AFHttpClientManager *)manager
requestPath:(NSString *)pathUrl
bodyParams:(NSDictionary *)params
successBlock:(void (^)(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject))successBlock
failureBlock:(void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failureBlock {
// 发起请求
if (requestMethod == RequestMethod_Get) {
manager.task = [manager GET:pathUrl parameters:params progress:nil success:successBlock failure:failureBlock];
}else if (requestMethod == RequestMethod_Post) {
manager.task = [manager POST:pathUrl parameters:params progress:nil success:successBlock failure:failureBlock];
}else if (requestMethod == RequestMethod_Put) {
manager.task = [manager PUT:pathUrl parameters:params success:successBlock failure:failureBlock];
}else if (requestMethod == RequestMethod_Delete) {
manager.task = [manager DELETE:pathUrl parameters:params success:successBlock failure:failureBlock];
}else if (requestMethod == RequestMethod_Patch) {
manager.task = [manager PATCH:pathUrl parameters:params success:successBlock failure:failureBlock];
}else if (requestMethod == RequestMethod_HEAD){
manager.task = [manager HEAD:pathUrl parameters:params success:^(NSURLSessionDataTask * _Nonnull task) {
successBlock(task,nil);
} failure:failureBlock];
}
}
// 文件上传
+ (void)uploadFileWithManager:(AFHttpClientManager *)manager
requestPath:(NSString *)pathUrl
bodyParams:(NSDictionary *)params
fileArray:(NSArray *)fileArray
fileType:(FileType)fileType
successBlock:(void (^)(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject))successBlock
failureBlock:(void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failureBlock{
[manager POST:pathUrl parameters:params constructingBodyWithBlock:^(id _Nonnull formData) {
if (fileType == FileType_Image) {
[VNHttpRequestManager imgFormdata:formData fileArray:fileArray];
}else{
[VNHttpRequestManager vedioFormdata:formData fileArray:fileArray];
}
} progress:^(NSProgress * _Nonnull uploadProgress) {
NSLog(@"上传进度:%f",uploadProgress.fractionCompleted);
} success:successBlock failure:failureBlock];
}
//音、视频上传
+ (void)vedioFormdata:(id _Nonnull)formData
fileArray:(NSArray *)fileArray{
NSString *type = [[fileArray.firstObject componentsSeparatedByString:@"."] lastObject];
for (NSString *filePath in fileArray) {
NSDate *date = [NSDate date];
NSDateFormatter *formormat = [[NSDateFormatter alloc]init];
[formormat setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateString = [formormat stringFromDate:date];
NSString *fileName = [NSString stringWithFormat:@"%@.%@",dateString,type];
[formData appendPartWithFileURL:[NSURL fileURLWithPath:filePath] name:@"file" fileName:fileName mimeType:@"wav/mp4/amr/mp3" error:nil];
}
}
//图片上传处理
+ (void)imgFormdata:(id _Nonnull)formData
fileArray:(NSArray *)fileArray{
NSString *type = [[fileArray.firstObject componentsSeparatedByString:@"."] lastObject];
for (NSString *imgPath in fileArray) {
UIImage * image =[UIImage imageWithContentsOfFile:imgPath];
NSDate *date = [NSDate date];
NSDateFormatter *formormat = [[NSDateFormatter alloc]init];
[formormat setDateFormat:@"yyyyMMddHHmmss"];
NSString *dateString = [formormat stringFromDate:date];
NSString *fileName = [NSString stringWithFormat:@"%@.%@",dateString,type];
NSData *imageData = UIImageJPEGRepresentation(image, 1);
double scaleNum = (double)300*1024/imageData.length;
NSLog(@"图片压缩率:%f",scaleNum);
if(scaleNum <1){
imageData = UIImageJPEGRepresentation(image, scaleNum);
}else{
imageData = UIImageJPEGRepresentation(image, 0.1);
}
[formData appendPartWithFileData:imageData name:@"image" fileName:fileName mimeType:@"image/jpg/png/jpeg"];
}
}
// unicode 编码汉化
+(NSString *)replaceUnicode:(NSString*)unicodeStr{
NSString *tempStr1=[unicodeStr stringByReplacingOccurrencesOfString:@"\\u"withString:@"\\U"];
NSString *tempStr2=[tempStr1 stringByReplacingOccurrencesOfString:@"\""withString:@"\\\""];
NSString *tempStr3=[[@"\""stringByAppendingString:tempStr2]stringByAppendingString:@"\""];
NSData *tempData=[tempStr3 dataUsingEncoding:NSUTF8StringEncoding];
NSString* returnStr = [NSPropertyListSerialization propertyListWithData:tempData options:NSPropertyListImmutable format:NULL error:NULL];
return [returnStr stringByReplacingOccurrencesOfString:@"\\r\\n"withString:@"\n"];
}
// 不正规json 序列化
+ (NSDictionary *)josnSerialization:(NSDictionary *)json{
if (json) {
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:json options:NSJSONWritingPrettyPrinted error:nil];
NSDictionary *content = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];//转换数据格式
return content;
}
return nil;
}
//get object(NSArray、NSDictionary)from JSON.NSData json序列化
+ (void)getObjectFromJSONData:(NSData *)data
complement:(void(^)(NSError *error, id jsonObject))complement{
id jsonObject = nil;
if (data.length != 0)
{
NSError *error = nil;
jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
if (!jsonObject)
{
NSString *strJSON = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
jsonObject = [VNHttpRequestManager replaceUnicode:strJSON];
#ifdef DEBUG
NSLog(@"数据解析错误 -JSONValue failed. Error trace is: %@,\n JSON:%@", error,strJSON);
#endif
if (!jsonObject) {
complement(error,nil);
return;
}
}
}
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonObject
options:NSJSONWritingPrettyPrinted
error:nil];
NSString *strResponse = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
if ([strResponse containsString:@"\\u"]) {
strResponse = [VNHttpRequestManager replaceUnicode:strResponse];
}
NSLog(@"Response Value = %@",strResponse );
complement(nil,jsonObject);
}
//获取错误code对应状态
+ (void)getErrorInfo:(NSError * _Nonnull )error infoData:(ServerResponseInfo *)infoData{
if (error.code == -1009) {
infoData.errorMessage = @"无网络连接";
}else if (error.code == -1001){
infoData.errorMessage = @"请求超时";
}else if (error.code == -1003){
infoData.errorMessage = @"找不到主机";
}else if (error.code == -1004){
infoData.errorMessage = @"服务器没有启动";
}else{
infoData.errorMessage = @"其他错误";
}
if (infoData.httpCode == 200) {
infoData.httpMessage = @"请求成功";
}else if (infoData.httpCode > 200 && infoData.httpCode < 207){
infoData.httpMessage = @"请求成功,服务器未响应";
}else if(infoData.httpCode == 400){
infoData.httpMessage = @"请求body参数有误";
}else if(infoData.httpCode == 401){
infoData.httpMessage = @"未授权,身份验证出问题";
}else if(infoData.httpCode == 403){
infoData.httpMessage = @"禁止访问";
}else if(infoData.httpCode == 404){
infoData.httpMessage = @"请求路径找不到";
}else if(infoData.httpCode > 499 && infoData.httpCode < 506){
infoData.httpMessage = @"服务器错误";
}else{
infoData.httpMessage = @"其他错误";
}
}
+ (void)netWorkReachability:(void(^)(NSString *))currentStatus{
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
[manager startMonitoring];
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
switch (status) {
case AFNetworkReachabilityStatusUnknown:
{
//未知网络
NSLog(@"未知网络");
currentStatus(@"未知网络");
}
break;
case AFNetworkReachabilityStatusNotReachable:
{
//无法联网
currentStatus(@"无网络网");
}
break;
case AFNetworkReachabilityStatusReachableViaWWAN:
{
//手机自带网络
NSLog(@"当前使用的是2g/3g/4g网络");
currentStatus(@"手机网络");
}
break;
case AFNetworkReachabilityStatusReachableViaWiFi:
{
//WIFI
NSLog(@"当前在WIFI网络下");
currentStatus(@"当前在WIFI网络下");
}
}
}];
}
@end
@implementation ServerResponseInfo
@end
// NSURLErrorUnknown = -1,
// NSURLErrorCancelled = -999,
// NSURLErrorBadURL = -1000,
// NSURLErrorTimedOut = -1001,
// NSURLErrorUnsupportedURL = -1002,
// NSURLErrorCannotFindHost = -1003,
// NSURLErrorCannotConnectToHost = -1004,
// NSURLErrorDataLengthExceedsMaximum = -1103,
// NSURLErrorNetworkConnectionLost = -1005,
// NSURLErrorDNSLookupFailed = -1006,
// NSURLErrorHTTPTooManyRedirects = -1007,
// NSURLErrorResourceUnavailable = -1008,
// NSURLErrorNotConnectedToInternet = -1009,
// NSURLErrorRedirectToNonExistentLocation = -1010,
// NSURLErrorBadServerResponse = -1011,
// NSURLErrorUserCancelledAuthentication = -1012,
// NSURLErrorUserAuthenticationRequired = -1013,
// NSURLErrorZeroByteResource = -1014,
// NSURLErrorCannotDecodeRawData = -1015,
// NSURLErrorCannotDecodeContentData = -1016,
// NSURLErrorCannotParseResponse = -1017,
// NSURLErrorInternationalRoamingOff = -1018,
// NSURLErrorCallIsActive = -1019,
// NSURLErrorDataNotAllowed = -1020,
// NSURLErrorRequestBodyStreamExhausted = -1021,
// NSURLErrorFileDoesNotExist = -1100,
// NSURLErrorFileIsDirectory = -1101,
// NSURLErrorNoPermissionsToReadFile = -1102,
// NSURLErrorSecureConnectionFailed = -1200,
// NSURLErrorServerCertificateHasBadDate = -1201,
// NSURLErrorServerCertificateUntrusted = -1202,
// NSURLErrorServerCertificateHasUnknownRoot = -1203,
// NSURLErrorServerCertificateNotYetValid = -1204,
// NSURLErrorClientCertificateRejected = -1205,
// NSURLErrorClientCertificateRequired = -1206,
// NSURLErrorCannotLoadFromNetwork = -2000,
// NSURLErrorCannotCreateFile = -3000,
// NSURLErrorCannotOpenFile = -3001,
// NSURLErrorCannotCloseFile = -3002,
// NSURLErrorCannotWriteToFile = -3003,
// NSURLErrorCannotRemoveFile = -3004,
// NSURLErrorCannotMoveFile = -3005,
// NSURLErrorDownloadDecodingFailedMidStream = -3006,
// NSURLErrorDownloadDecodingFailedToComplete = -3007
请求样例 POST 方式
[VNHttpRequestManager sendJSONRequestWithMethod:RequestMethod_Post pathUrl:@"https://wesus.api.cogniive.misoft.com/pid/v1.0/identification" params:@{@"locale":@"en-us"} complement:^(ServerResponseInfo *serverInfo) {
if (serverInfo.isSuccess) {
}
}];
二、Swift AFRequestManager 封装类
此类基于 Alamofire 封装具体思想雷同,大家看用例
// AFRequestManager.swift
// SwiftGrammar
//
// Created by guohq on 2018/7/20.
// Copyright © 2018年 guohq. All rights reserved.
//
import UIKit
import Alamofire
public enum FILE_TYPE{
case FILE_TYPE_NORMAL //
case FILE_TYPE_IMG // 图片
case FILE_TYPE_VOICE_VIDEO // 音频、视频
}
// MARK: - 下载状态
public enum DownloadStatus {
case downloading //下载中
case suspend //暂停
case complete // 完成
}
fileprivate enum RequestType{
case RequestType_UPLOAD // 上传文件
case RequestType_REQUEST // 数据交互
}
// 超时时间设置
struct RequestTimeOut {
static var timeOut:TimeInterval = 20
// 结构体 属于 值类型 要在 实例 或 类 方法中修改成员变量 需要添加 mutating 关键字(结构体变量赋值是在初始化时进行的,之后想修改必须添加mutating)
}
// 超时时间设置 ---> 10
fileprivate var manager: Alamofire.SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = RequestTimeOut.timeOut
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return Alamofire.SessionManager(configuration: configuration)
}();
class AFRequestManager: NSObject {
/// 下载任务管理
fileprivate var downloadTasks = [String: DownloadTaskManager]()
// 单例
private static let singleManager = AFRequestManager();
// 私有化构造方法
override init() {}
// 公开类方法 获取单例类 默认超时时间20秒
private class func defaultSingleManager() -> AFRequestManager{
return singleManager
}
// 请求头设置
private func requestHeaderSetting(header:[String:String]? = [:]) -> HTTPHeaders{
var headers : HTTPHeaders = [String: String]()
headers["Ocp-Apim-Subscription-Key"] = "发送到发送到发送到发送到"
headers["Accept"] = "application/json"
for key in (header?.keys)!{
headers[key] = header![key]
}
return headers;
}
/** 请求回调处理 */
typealias AFSProgressBlock = (Double) -> Void;
typealias AFSComplementBlock = (AFSRequestSuccess?,AFSRequestErrorInfo?,Bool) -> Void;
/**
请求调用方法
@param method 请求方法 get post put delete.... 默认post
@param requestUrl 请求地址
@param parmas 请求体
@param complement 回调方法
*/
public class func sendRequestNet(method:HTTPMethod,
requestUrl:URLConvertible,
parmas:Parameters,
headers:HTTPHeaders = SessionManager.defaultHTTPHeaders,
complement:@escaping AFSComplementBlock){
var headers : HTTPHeaders = AFRequestManager.defaultSingleManager().requestHeaderSetting(header: headers)
headers["Content-Type"] = "application/json;charset=utf-8"
AFRequestManager().senderRequestHandle(method: method,
requestUrl: requestUrl,
parmas: parmas,
headers:headers,
complement: complement)
}
/**
上传文件
@param fileArr 文件list
@param requestUrl 请求地址
@param parmas 请求体
@param fileType 文件类型 两类:图片 或者 视频、音频
@param progressBlock 上传文件进度
@param complement 回调方法
*/
public class func uploadFielRequest(fileArr:[String],
requestUrl:URLConvertible,
param:Parameters,
fileType:FILE_TYPE,
headers:HTTPHeaders = SessionManager.defaultHTTPHeaders,
progressBlock:@escaping AFSProgressBlock,
complement:@escaping AFSComplementBlock){
var headers : HTTPHeaders = AFRequestManager.defaultSingleManager().requestHeaderSetting(header: headers)
headers["Content-Type"] = "multipart/form-data"
AFRequestManager().senderRequest(requestType: RequestType.RequestType_UPLOAD,
fileArr: fileArr,
requestUrl: requestUrl,
param: param,
headers:headers,
fileType: fileType,
progressBlock: progressBlock,
complement: complement)
}
// 请求特殊处理
private func senderRequestHandle(method:HTTPMethod,
requestUrl:URLConvertible,
parmas:Parameters,
headers:HTTPHeaders,
redirectCount:Int = 0,
complement:@escaping AFSComplementBlock) {
self.senderRequest(requestType: RequestType.RequestType_REQUEST,
method: method,
requestUrl: requestUrl,
param: parmas,
headers:headers,
complement:{(response,errorInfo,statuCode) in
// 请求重定向重复请求最多两次递归
if errorInfo?.httpCode == 302 && redirectCount < 2{
let redirectCount = 1 + redirectCount
self.senderRequestHandle(method: method, requestUrl: requestUrl, parmas: parmas,headers:headers, redirectCount: redirectCount, complement: complement)
}else{
complement(response,errorInfo,statuCode)
}
})
}
/**
@param requestType 请求类型 上传或者文件交互
@param fileArr 文件list
@param method 请求方法 get post put delete.... 默认post
@param requestUrl 请求地址
@param parmas 请求体
@param fileType 文件类型 两类:图片 或者 视频、音频
@param progressBlock 上传文件进度
@param complement 回调方法
*/
private func senderRequest(requestType:RequestType,
method:HTTPMethod = .post,
fileArr:[String] = [],
requestUrl:URLConvertible,
param:Parameters = [:],
headers:HTTPHeaders = [:],
fileType :FILE_TYPE = FILE_TYPE.FILE_TYPE_NORMAL,
progressBlock :@escaping AFSProgressBlock = {_ in},
complement:@escaping AFSComplementBlock = {_,_,_ in}) {
let completionHandler = self.completionHandler(param: param, complement: complement);
let encodingCompletion = self.encodingCompletion(param: param, progressBlock:progressBlock,complement:complement)
if requestType == RequestType.RequestType_REQUEST {
// 发起请求
AFRequestManager.defaultSingleManager().startReqest(method: method, requestUrl: requestUrl, parma: param, headers:headers, completionHandler: completionHandler)
}else{
// 上传文件
AFRequestManager.defaultSingleManager().uploadFile(fileArr: fileArr, requestUrl: requestUrl, param: param, fileType: fileType, headers:headers, encodingCompletion: encodingCompletion)
}
}
// 请求回调函数
@discardableResult
private func completionHandler(param:Parameters = [:],
complement:@escaping AFSComplementBlock) -> (DataResponse) -> Void{
let completionHandler:(DataResponse) -> Void = { (response) in
print("请求路径: ====== \(String(describing: response.request?.url?.absoluteString))") // original url request
print("参数 : ====== \(param)") // 请求参数
print("请求状态: ====== \(response.result)") // 请求结果
let str = String(data:response.data!, encoding: String.Encoding.utf8)!
print("响应内容: ====== \(str.unicodeStr)")
// 请求处理
self.handleResponserData(response: response,complement: complement);
}
return completionHandler
}
// 上传文件回调函数
@discardableResult
private func encodingCompletion(param:Parameters = [:],
progressBlock :@escaping AFSProgressBlock = {_ in},
complement:@escaping AFSComplementBlock)
-> ((SessionManager.MultipartFormDataEncodingResult) -> Void)?{
let encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)? = {(encodingResult) in
switch encodingResult {
case .success(let upload, _, _):
//获取上传进度
upload.uploadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
progressBlock(progress.fractionCompleted);
print( progress.fractionCompleted)
};
upload.responseJSON { response in
print("请求路径: ====== \(String(describing: response.request))") // original url request
print("参数 : ====== \(param)") // 请求参数
print("请求状态: ====== \(response.result)") // 请求结果
let str = String(data:response.data!, encoding: String.Encoding.utf8)!
print("响应内容: ====== \(str.unicodeStr)")
// 请求处理
self.handleResponserData(response: response, complement: complement);
}
case .failure(let encodingError):
self.handleRequestErrorData(response: nil, error_data: encodingError as NSError, complement: complement)
}
}
return encodingCompletion
}
/**
向服务器发起请求
@param encoding 请求编码类型 JSONEncoding、URLEncoding、PropertyListEncoding
@param method 请求方法 get post put delete....
@param requestUrl 请求地址
@param parmas 请求体
*/
private func startReqest(method:HTTPMethod,
requestUrl:URLConvertible,
parma:Parameters,
headers:HTTPHeaders = [:],
completionHandler:@escaping (DataResponse) -> Void){
manager.request(requestUrl, method: method, parameters: parma, encoding: JSONEncoding.default, headers: headers) .validate()
.responseJSON(completionHandler: completionHandler)
}
/**
向服务器发起请求
@param fileArr 文件list
@param method 请求方法 get post put delete....
@param requestUrl 请求地址
@param parmas 请求体
@param encodingCompletion 上传回调
*/
private func uploadFile(fileArr:[String],
requestUrl:URLConvertible,
param:Parameters,
fileType:FILE_TYPE,
headers:HTTPHeaders = [:],
encodingCompletion: ((SessionManager.MultipartFormDataEncodingResult) -> Void)?) {
let multipartFormData :(MultipartFormData) -> Void = { (multipartFormData) in
if fileType == FILE_TYPE.FILE_TYPE_IMG {
self.uploadIMGFile(multipartFormData: multipartFormData,
fileArr: fileArr)
}else{
self.uploadVideoVoiceFile(multipartFormData: multipartFormData,
fileArr: fileArr)
}
}
manager.upload(multipartFormData: multipartFormData, to: requestUrl,headers: headers,encodingCompletion:encodingCompletion)
}
/** 上传图片 */
private func uploadIMGFile(multipartFormData:MultipartFormData,fileArr:[String]){
let fileType:String = (fileArr.first?.components(separatedBy: ".").last)!
for filePath:String in fileArr {
let nowTime = self.getCurrentTime()
let fileName = nowTime + fileType
let image:UIImage = UIImage(contentsOfFile: filePath)!
var imgData = UIImageJPEGRepresentation(image, 1)
let scaleNum:Double = Double(300*1024.0 / Float(imgData!.count))
if(scaleNum < 1){
imgData = UIImageJPEGRepresentation(image, CGFloat(scaleNum))
}else{
imgData = UIImageJPEGRepresentation(image, 0.1)
}
multipartFormData.append(imgData!, withName: "image", fileName: fileName, mimeType: "jpg/png");
}
}
/** 上传视频或者音频 */
private func uploadVideoVoiceFile(multipartFormData:MultipartFormData,fileArr:[String]){
let fileType:String = (fileArr.first?.components(separatedBy: ".").last)!
for filePath:String in fileArr {
let nowTime = self.getCurrentTime()
let fileName = nowTime + fileType
let data1 = NSData(contentsOfFile: filePath)! as Data // let mp4Path = URL(fileURLWithPath: filePath)
multipartFormData.append(data1, withName: "file", fileName: fileName, mimeType: "map4/wav/amr");
}
}
// 获取当前时间
private func getCurrentTime() -> String{
let date = NSDate()
let timeFormatter = DateFormatter()
timeFormatter.dateFormat = "yyyyMMddHHmmss"
let strNowTime = timeFormatter.string(from: date as Date) as String
return strNowTime
}
/** 响应数据处理 */
private func handleResponserData(response:DataResponse,complement:AFSComplementBlock){
if response.result.error != nil { // 服务器未返回数据
self.handleRequestErrorData( response: response, error_data: response.result.error! as NSError,complement: complement);
}else if let value = response.result.value { // 服务器又返回数据
if (value as? NSDictionary) == nil && (value as? NSArray) == nil { // 返回格式不对
self.handleRequestSuccessWithFaliedBlcokData(complement: complement)
}else{
self.handleRequestSuccessData(value: value, complement:complement);
}
}
}
/** 响应数据出错处理 */
private func handleRequestErrorData(response:DataResponse?,error_data:NSError?,complement:AFSComplementBlock){
var error = NSError()
var errorInfo = AFSRequestErrorInfo()
if response != nil{
print("错误提示: \(String(describing: response!.error))") // http url response
print("响应信息: \(String(describing: response!.response))")
if let code = response?.response?.statusCode{
errorInfo.httpCode = code
}
if let er = response?.result.error as NSError?{
error = er
}
}else{
error = error_data!
print(error)
for item in error.userInfo {
print("error ++++++ \(item)")
}
}
errorInfo.code = error.code;
errorInfo.error = error;
if let head = response?.response?.allHeaderFields as? [String:String] {
errorInfo.responseHeader = head
}
if ( errorInfo.code == -1009 ) {
errorInfo.message = "无网络连接"
}else if ( errorInfo.code == -1001 ){
errorInfo.message = "请求超时"
}else if ( errorInfo.code == -1005 ){
errorInfo.message = "网络连接丢失(服务器忙)";
}else if ( errorInfo.code == -1004 ){
errorInfo.message = "服务器没有启动"
}else{
errorInfo.message = "其他错误"
}
errorInfo.httpMessage = HttpStatusCode.codeMessage(code: errorInfo.httpCode)
complement(nil,errorInfo,false)
}
/** 响应数据解析出问题 */
private func handleRequestSuccessData(value:Any!,complement:AFSComplementBlock){
var success = AFSRequestSuccess();
if let result = value as? NSArray{
success.responseArr = result
}else{
success.responseDic = value as? NSDictionary
}
complement(success ,nil,true);
}
/** 服务器返回数据解析出错*/
private func handleRequestSuccessWithFaliedBlcokData(complement:AFSComplementBlock){
var errorInfo = AFSRequestErrorInfo();
errorInfo.code = -1;
errorInfo.message = "数据解析出错";
complement(nil,errorInfo,false);
}
/**
向服务器发起请求
@param encoding 请求编码类型 JSONEncoding、URLEncoding、PropertyListEncoding
@param method 请求方法 get post put delete....
@param requestUrl 请求地址
@param parmas 请求体
@param destination 下载文件地址
*/
@discardableResult
public class func downloadFile( method:HTTPMethod = .get,
requestUrl:URLConvertible,
parma:Parameters = [:],
headers:HTTPHeaders = SessionManager.defaultHTTPHeaders,
fileName:String,
downProgress:@escaping (Double) -> Void,
completion: @escaping (Alamofire.Result,String?)->()) -> DownloadTaskManager{
let headers : HTTPHeaders = AFRequestManager.defaultSingleManager().requestHeaderSetting(header:headers)
let downloadManager = DownloadTaskManager().download(requestUrl, method: method, parameters: parma, headers: headers, fileName:fileName)
downloadManager.downloadProgress(progress: downProgress).response(completion: completion)
AFRequestManager.defaultSingleManager().downloadTasks[requestUrl as! String] = downloadManager
downloadManager.downCompletion = { (urlPath) in
deleteResumeData(urlPath: urlPath)
}
return downloadManager
}
public class func getDownloadStatus(pathUrl:String) -> DownloadStatus{
let taskRequest = AFRequestManager.defaultSingleManager().downloadTasks[pathUrl]
return taskRequest?.downloadStatus ?? .suspend
}
public class func downloadCancle(pathUrl:String){
let taskRequest = AFRequestManager.defaultSingleManager().downloadTasks[pathUrl]
taskRequest?.downloadCancle()
}
//
public class func downloadFilePath(pathUrl:String) -> String{
let taskRequest = AFRequestManager.defaultSingleManager().downloadTasks[pathUrl]
return taskRequest?.downFilePath ?? "not found filepath"
}
}
/** 访问出错具体原因 */
struct AFSRequestErrorInfo {
var code = 0 // code 值
var httpCode = 0 // http 响应状态码
var httpMessage = "" // http 请求提示
var message = "" // 请求提示
var error = NSError(); // 错误信息
var responseHeader:[String:String]? // 请求响应header
}
/** 响应数据 */
struct AFSRequestSuccess {
var responseDic:NSDictionary?
var responseArr:NSArray = NSArray()
}
fileprivate enum HttpMessage:String{
case success = "成功"
case paramError = "请求body参数有误"
case urlError = "请求路径找不到"
case accessUnnormal = "未授权,身份验证出问题"
case binaryAccess = "禁止访问"
case serviceError = "服务器错误"
case successRequest = "请求成功,服务器未响应"
case unnormal = "其他错误"
}
/** http 响应码对应状态 */
fileprivate struct HttpStatusCode {
static func codeMessage(code:Int) -> String {
var message:String = ""
switch code {
case 200:
message = HttpMessage.success.rawValue
break
case 201,202,203,204,205,206:
message = HttpMessage.successRequest.rawValue
break
case 400:
message = HttpMessage.paramError.rawValue
break
case 401:
message = HttpMessage.accessUnnormal.rawValue
break
case 403:
message = HttpMessage.binaryAccess.rawValue
break
case 404:
message = HttpMessage.urlError.rawValue
break
case 500,501,502,503,504,505:
message = HttpMessage.serviceError.rawValue
break
default:
message = HttpMessage.unnormal.rawValue
break
}
return message
}
}
// MARK: - taskManager
public class DownloadTaskManager {
fileprivate var downloadRequest: DownloadRequest?
fileprivate var downloadStatus: DownloadStatus = .suspend
fileprivate var downCompletion: ((String)->())?
fileprivate var downUrl: String?
fileprivate var downFilePath: String?
/** 初始化 --- 生成key
* Parameters:
* - url: url
* - parameters: 参数
* - dynamicParams: 变化的参数,例如 时间戳-token 等
*/
@discardableResult
fileprivate func download(
_ url: URLConvertible,
method: HTTPMethod = .get,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
headers: HTTPHeaders? = nil,
fileName: String?)
-> DownloadTaskManager
{
let destination = downloadDestination(fileName)
downUrl = url as? String
let result = getResumeData(urlPath: downUrl!)
if let resumData = result{
downloadRequest = manager.download(resumingWith:resumData , to: destination)
}else{
downloadRequest = manager.download(url, method: method, parameters: parameters, encoding: encoding, headers: headers, to: destination)
}
downloadStatus = .downloading
return self
}
fileprivate func downloadCancle(){
downloadRequest?.cancel()
}
/// 下载进度
@discardableResult
fileprivate func downloadProgress(progress: @escaping ((Double) -> Void)) -> DownloadTaskManager {
downloadRequest?.downloadProgress(closure: { (pro) in
progress(pro.fractionCompleted)
})
return self
}
/// 响应
fileprivate func response(completion: @escaping (Alamofire.Result,String?)->()) {
downloadRequest?.responseData(completionHandler: {[weak self] (response) in
switch response.result {
case .success:
print("响应者状态 \(response)")
self?.downloadStatus = .complete
let str = response.destinationURL?.absoluteString
completion(Alamofire.Result.success(str!),self?.downFilePath)
self?.downCompletion!(str!)
case .failure(let error):
print("下载出错 \(error)")
self?.downloadStatus = .suspend
saveResumeData(pathUrl: (self?.downUrl!)!, resumData: response.resumeData! )
completion(Alamofire.Result.failure(error),self?.downFilePath)
}
})
}
/**
下载文件位置
* - Parameter fileName: 自定义文件名
* - Returns: 下载位置
*/
private func downloadDestination(_ fileName: String?) -> DownloadRequest.DownloadFileDestination {
let destination: DownloadRequest.DownloadFileDestination = {[weak self] _, response in
let cachesURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
if let fileName = fileName {
let fileURL = cachesURL.appendingPathComponent(fileName)
self?.downFilePath = fileURL.absoluteString
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
} else {
let fileURL = cachesURL.appendingPathComponent(response.suggestedFilename!)
self?.downFilePath = fileURL.absoluteString
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
}
return destination
}
}
// 保存切片数据
fileprivate func saveResumeData(pathUrl:String,resumData:Data? = nil){
let info:UserDefaults = UserDefaults.standard
if let resumData = resumData{
info.set(resumData, forKey: pathUrl)
}
}
// 获取切片数据
fileprivate func getResumeData(urlPath:String) -> Data?{
let info:UserDefaults = UserDefaults.standard
return info.object(forKey: urlPath) as? Data
}
// 清空数据
fileprivate func deleteResumeData(urlPath:String){
let info:UserDefaults = UserDefaults.standard
info.removeObject(forKey: urlPath)
}
// Unicode 编码转码
extension String{
var unicodeStr:String{
let str1:String = self.replacingOccurrences(of: "\\u", with: "\\U")
let str2 = str1.replacingOccurrences(of: "\"", with: "\\\"")
let str3:String = "\"" + str2 + "\""
let tempData = str3.data(using: String.Encoding.utf8)
var returnStr = ""
do{
returnStr = try PropertyListSerialization.propertyList(from: tempData!, options:PropertyListSerialization.MutabilityOptions(rawValue: String.Encoding.utf8.rawValue), format: nil) as! String
}catch{
print(error)
}
return returnStr.replacingOccurrences(of: "\\r\\n", with: "\n")
}
}
用例
post
AFRequestManager.sendRequestNet(method: .post, requestUrl: "http://app.u17.com/v3/appV3_3/ios/phone/comic/boutiqueListNew", parmas: ["sexType":"1","key":"fabe6953ce6a1b8738bd2cabebf893a472d2b6274ef7ef6f6a5dc7171e5cafb14933ae65c70bceb97e0e9d47af6324d50394ba70c1bb462e0ed18b88b26095a82be87bc9eddf8e548a2a3859274b25bd0ecfce13e81f8317cfafa822d8ee486fe2c43e7acd93e9f19fdae5c628266dc4762060f6026c5ca83e865844fc6beea59822ed4a70f5288c25edb1367700ebf5c78a27f5cce53036f1dac4a776588cd890cd54f9e5a7adcaeec340c7a69cd986:::open","target":"U17_3.0","version":"3.3.3","v":"3320101","model":"Simulator","device_id":"29B09615-E478-4320-8E6A-55B1DE48CB36","time":Int32(Date().timeIntervalSince1970)] ) { (response, errorInfo, resultStatus) in
if resultStatus{
print("===")
}
}
断点下载
let downFile = "http://audio.xmcdn.com/group11/M01/93/AF/wKgDa1dzzJLBL0gCAPUzeJqK84Y539.m4a"
let downloadStatus = AFRequestManager.getDownloadStatus(pathUrl: downFile)
switch downloadStatus {
case .complete:
let filePath = AFRequestManager.downloadFilePath(pathUrl:downFile)
print("文件路径 ===== \(filePath)")
break
case .suspend:
AFRequestManager.downloadFile(requestUrl: downFile, headers:["123":"guohong"],fileName: "gdsfa.mp4", downProgress: { (progress) in
print("\(progress)")
}) { (resultStr,filePath) in
print("结果字符串 \(resultStr)")
}
break
case .downloading:
AFRequestManager.downloadCancle(pathUrl: downFile)
break
}
上传文件
let request:String = "https://westus.api.cognitive.microsoft.com/spid/v1.0/identificationProfiles/12312312/enroll?shortAudio=true"
AFRequestManager.uploadFielRequest(fileArr: ["/Users/用户名/Desktop/文件本地路径], requestUrl: request, param: [:], fileType: FILE_TYPE.FILE_TYPE_VOICE_VIDEO,headers:[:], progressBlock: { (progress) in
}) { (response, errorInfo, resultStatus) in
print("=======")
}
通过 RequestTimeOut.timeOut = 10 来设置超时时间