// // RequestHandler.m // Giwa // // Created by Jason Lee on 12/16/14. // Copyright (c) jasondevelop. All rights reserved. // #import "JDObject.h" #import "AFHTTPRequestOperation.h" #import "JDJSONModel.h" #import "RequestHandler.h" #import "AFHTTPRequestOperationManager.h" #import "AFHTTPRequestOperationManager+Synchronous.h" #define NSEUCKREncoding -2147481280 @interface RequestHandler () { NSString *_requestPath; } @end @implementation RequestHandler #pragma mark - URL Encoding - (NSString *)URLEncodedString:(NSString *)string { return [string stringByAddingPercentEscapesUsingEncoding:NSEUCKREncoding]; // NSString *encodedString = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, // (CFStringRef)string, // NULL, // (CFStringRef)@"!*'();:@&=+$,/?%#[]", // kCFStringEncodingUTF8); // return encodedString; } //- (NSString*)URLDecodedString:(NSString *)string //{ // // // // NSString *result = (__bridge NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, // (CFStringRef)string, // CFSTR(""), // kCFStringEncodingUTF8); // return result; //} #pragma mark - Prepare Request - (void)sendRequest { [[JDFacade facade] loadIndicator:YES allowUserInteraction:NO]; } - (void)finishRequest { [[JDFacade facade] loadIndicator:NO allowUserInteraction:YES]; } #pragma mark - URL Request - (void)sendAsyncRequestURLString:(NSString *)URLString method:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendRequest]; NSString *encodURLString = [self URLEncodedString:[NSString stringWithFormat:@"%@%@", URLString, path]]; NSLog(@"URL=%@", encodURLString); NSLog(@"PARAM=%@", parameters); NSError *error = nil; BOOL hasFile = NO, isDataImage = NO, isMultipartForm = parameters[ksHTTPMultipartForm] && [parameters[ksHTTPRequestPOST] boolValue] ? YES : NO; NSData *dataToUpload = nil; NSString *dataParameter = nil; NSInteger i = 0; for (NSObject *obj in parameters.allValues) {//파일형식이 있는지 체크, if (!hasFile && ([obj isKindOfClass:[UIImage class]] || [obj isKindOfClass:[NSData class]])) { isDataImage = [obj isKindOfClass:[UIImage class]]; dataToUpload = isDataImage ? UIImageJPEGRepresentation((UIImage *)obj, 1.0) : (NSData *)obj; dataParameter = parameters.allKeys[i]; hasFile = YES; break; } i++; } NSMutableURLRequest *request = nil; if (!hasFile && !isMultipartForm) {//no image request = [[AFHTTPRequestSerializer serializer] requestWithMethod:method URLString:encodURLString parameters:parameters error:&error]; } else {//Multipart-form NSMutableDictionary *tmpParams = [NSMutableDictionary dictionaryWithDictionary:parameters]; [tmpParams removeObjectForKey:dataParameter]; request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:method URLString:encodURLString parameters:tmpParams constructingBodyWithBlock:^(id formData) { NSString *fileName = isDataImage ? @"tmp.jpg" : @"tmp.txt"; NSString *mimeType = isDataImage ? @"image/jpeg" : @"application/json"; //text/plain [formData appendPartWithFileData:dataToUpload name:dataParameter fileName:fileName mimeType:mimeType]; } error:&error]; } AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; op.responseSerializer = [AFJSONResponseSerializer serializer]; [[JDFacade facade] setCurrentOperation:op]; [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { [self finishRequest]; NSLog(@"\n\nJSON=%@\n\n", responseObject); if (completion) { completion(responseObject); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [self finishRequest]; if (failure) { failure(error); } }]; [[NSOperationQueue mainQueue] addOperation:op]; } - (void)sendAsyncPostRequestURL:(NSString *)URLString path:(NSString *)path parameters:(NSDictionary *)parameters completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendAsyncRequestURLString:URLString method:ksHTTPRequestPOST path:(NSString *)path parameters:parameters completion:completion failure:failure]; } - (void)sendAsyncGetRequestURL:(NSString *)URLString path:(NSString *)path parameters:(NSDictionary *)parameters completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendAsyncRequestURLString:URLString method:ksHTTPRequestGET path:(NSString *)path parameters:parameters completion:completion failure:failure]; } #pragma mark - 비동기 API 요청 - (void)sendAsyncGetRequestAPIPath:(NSString *)apiPath parameters:(NSDictionary *)parameters modelClass:(Class)modelClass completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendAsyncRequestAPIPath:apiPath method:ksHTTPRequestGET parameters:parameters modelClass:modelClass showLoadingView:YES completion:completion failure:failure]; } - (void)sendAsyncPostRequestAPIPath:(NSString *)apiPath parameters:(NSDictionary *)parameters modelClass:(Class)modelClass completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendAsyncRequestAPIPath:apiPath method:ksHTTPRequestPOST parameters:parameters modelClass:modelClass showLoadingView:YES completion:completion failure:failure]; } - (void)sendAsyncPostRequestAPIPath:(NSString *)apiPath parameters:(NSDictionary *)parameters modelClass:(Class)modelClass showLoadingView:(BOOL)showLoadingView completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { [self sendAsyncRequestAPIPath:apiPath method:ksHTTPRequestPOST parameters:parameters modelClass:modelClass showLoadingView:showLoadingView completion:completion failure:failure]; } - (void)sendAsyncRequestAPIPath:(NSString *)apiPath method:(NSString *)method parameters:(NSDictionary *)parameters modelClass:(Class)modelClass showLoadingView:(BOOL)showLoadingView completion:(RequestHandlerCompletionBlock)completion failure:(RequestHandlerFailureBlock)failure { _requestPath = apiPath; if (showLoadingView) { [self sendRequest]; } NSString *rootPath = API_ROOT_PATH; NSString *pathURL = [self URLEncodedString:[NSString stringWithFormat:@"%@%@%@", kAPIServer, rootPath, apiPath]]; NSLog(@"PATH=%@", pathURL); NSLog(@"PARAM=%@", parameters); NSError *error = nil; BOOL hasFile = NO, isDataImage = NO, isMultipartForm = parameters[ksHTTPMultipartForm] && [parameters[ksHTTPRequestPOST] boolValue] ? YES : NO; NSMutableArray *fileArray = nil; NSMutableArray *fileParams = nil; NSInteger index = 0; for (NSObject *obj in parameters.allValues) {//파일형식이 있는지 체크, if (([obj isKindOfClass:[UIImage class]] || [obj isKindOfClass:[NSData class]])) { if (!fileArray) { fileArray = [[NSMutableArray alloc] init]; fileParams = [[NSMutableArray alloc] init]; hasFile = YES; } isDataImage = [obj isKindOfClass:[UIImage class]]; [fileArray addObject:isDataImage ? UIImageJPEGRepresentation((UIImage *)obj, 1.0) : (NSData *)obj]; [fileParams addObject:parameters.allKeys[index]]; } index++; } NSMutableURLRequest *request = nil; if (!hasFile && !isMultipartForm) {//no file request = [[AFJSONRequestSerializer serializer] requestWithMethod:method URLString:pathURL parameters:parameters error:&error]; [request setHTTPMethod:method]; [request setTimeoutInterval:kDefaultTimeOut]; [request setValue:@"application/json;charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0]; #ifdef DEBUG_MODE language = @"ko"; #endif [request setValue:language forHTTPHeaderField:@"Accept-Language"]; } else {//Multipart-form NSMutableDictionary *tmpParams = [NSMutableDictionary dictionaryWithDictionary:parameters]; [tmpParams removeObjectForKey:fileParams]; request = [[AFJSONRequestSerializer serializer] multipartFormRequestWithMethod:method URLString:pathURL parameters:tmpParams constructingBodyWithBlock:^(id formData) { NSString *mimeType = isDataImage ? @"image/jpeg" : @"text/plain"; NSInteger i = 0; // NSString *name = [fileParams[i] substringToIndex:[fileParams[i] rangeOfString:@"_"].location]; NSString *name = fileParams[i]; for (NSData *dataToUpload in fileArray) { NSString *fileName = isDataImage ? [NSString stringWithFormat:@"tmp_%zd.jpg", i+1] : [NSString stringWithFormat:@"tmp_%zd.txt", i+1]; [formData appendPartWithFileData:dataToUpload name:name fileName:fileName mimeType:mimeType]; } } error:&error]; } [request setValue:self.authorization ? self.authorization : ksEmptyString forHTTPHeaderField:@"Authorization"]; [request setValue:self.homegrpId ? self.homegrpId : ksEmptyString forHTTPHeaderField:@"X-kneet-homegrp"]; AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; op.responseSerializer = [AFHTTPResponseSerializer serializer]; [JDFacade facade].currentOperation = op; [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, NSData *responseObject) { [self finishRequest]; NSString *JSONString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]; #ifndef PRODUCT_MODE NSLog(@"\n\nJSON=%@\n\n", JSONString); #endif id JSONModel = nil; NSError *error = nil; if (responseObject && responseObject.length) { id rawJSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error]; if (modelClass) { if ([rawJSON isKindOfClass:[NSArray class]]) { NSDictionary *JSONDic = @{@"list": rawJSON}; JSONModel = [[modelClass alloc] initWithDictionary:JSONDic error:&error]; } else { JSONModel = [[modelClass alloc] initWithString:JSONString error:&error]; } } else { JSONModel = rawJSON; } } // else { // error = [NSError errorWithDomain:@"RequestHandler" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"RESPONSE DATA is NULL"}]; // } if (error) {//오류 처리 [[JDFacade facade] retryAlert:MSG_ALERT_SERVER_FAIL completionHander:^{ [self sendAsyncRequestAPIPath:apiPath method:method parameters:parameters modelClass:modelClass showLoadingView:showLoadingView completion:completion failure:failure]; }]; return; } //쿠키 설정 NSArray* cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[operation.response allHeaderFields] forURL:operation.request.URL]; if (cookies && cookies.count > 0) { [self setCookies:cookies]; } if (completion) { completion(JSONModel); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { [self finishRequest]; NSLog(@"HTTPStatus=%zd\n%@", operation.response.statusCode, error.localizedDescription); NSString *JSONString = [[NSString alloc] initWithData:operation.responseData encoding:NSUTF8StringEncoding]; #ifndef PRODUCT_MODE NSLog(@"\n\nERROR=%@\n\n", JSONString); #endif JDErrorModel *jerror = [[JDErrorModel alloc] initWithString:JSONString error:&error]; BOOL isLoginView = [[JDFacade facade].currentViewController isKindOfClass:[NSClassFromString(@"LoginViewController") class]]; if (!isLoginView && [jerror.errorCode isEqualToString:API_RESPONSE_UNAUTHORIZED_TOKEN]) {//인증토큰이 만료된 경우, 로그인 이동 [[JDFacade facade] gotoLoginView]; } else if (failure && jerror) { failure(jerror ? jerror : error); } else { [[JDFacade facade] retryAlert:MSG_ALERT_SERVER_FAIL completionHander:^{ [self sendAsyncRequestAPIPath:apiPath method:method parameters:parameters modelClass:modelClass showLoadingView:showLoadingView completion:completion failure:failure]; }]; } }]; [[NSOperationQueue mainQueue] addOperation:op]; } #pragma mark - 동기 API 요청 - (id)sendSyncRequestAPIPath:(NSString *)apiPath method:(NSString *)method parameters:(NSDictionary *)parameters modelClass:(Class)modelClass showLoadingView:(BOOL)showLoadingView { if (showLoadingView) { [self sendRequest]; } NSString *rootPath = API_ROOT_PATH; NSString *pathURL = [self URLEncodedString:[NSString stringWithFormat:@"%@%@%@", kAPIServer, rootPath, apiPath]]; NSLog(@"PATH=%@", pathURL); NSLog(@"PARAM=%@", parameters); NSError *error = nil; NSMutableURLRequest *request = [[AFJSONRequestSerializer serializer] requestWithMethod:method URLString:pathURL parameters:parameters error:&error]; [request setHTTPMethod:method]; [request setTimeoutInterval:kDefaultTimeOut]; [request setValue:@"application/json;charset=UTF-8" forHTTPHeaderField:@"Content-Type"]; [request setValue:@"en" forHTTPHeaderField:@"Accept-Language"]; [request setValue:self.authorization ? self.authorization : ksEmptyString forHTTPHeaderField:@"Authorization"]; [request setValue:self.homegrpId ? self.homegrpId : ksEmptyString forHTTPHeaderField:@"X-kneet-homegrp"]; AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; op.responseSerializer = [AFHTTPResponseSerializer serializer]; [op start]; [op waitUntilFinished]; // Must call responseObject before checking the error NSData *responseObject = [op responseObject]; if (showLoadingView) { [self finishRequest]; } if (error) { return nil; } NSString *JSONString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]; #ifndef PRODUCT_MODE NSLog(@"\n\nJSON=%@\n\n", JSONString); #endif id JSONModel = nil; if (responseObject && responseObject.length) { id rawJSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error]; if (modelClass) { if ([rawJSON isKindOfClass:[NSArray class]]) { NSDictionary *JSONDic = @{@"list": rawJSON}; JSONModel = [[modelClass alloc] initWithDictionary:JSONDic error:&error]; } else { JSONModel = [[modelClass alloc] initWithString:JSONString error:&error]; } } else { JSONModel = rawJSON; } } return JSONModel; } - (id)sendSyncPostRequestAPIPath:(NSString *)apiPath parameters:(NSDictionary *)parameters modelClass:(Class)modelClass showLoadingView:(BOOL)showLoadingView { return [self sendSyncRequestAPIPath:apiPath method:ksHTTPRequestPOST parameters:parameters modelClass:modelClass showLoadingView:showLoadingView]; } - (id)sendSyncGetRequestAPIPath:(NSString *)apiPath parameters:(NSDictionary *)parameters modelClass:(Class)modelClass showLoadingView:(BOOL)showLoadinView { return [self sendSyncRequestAPIPath:apiPath method:ksHTTPRequestGET parameters:parameters modelClass:modelClass showLoadingView:showLoadinView]; } #pragma mark - Cookies - (void)setCookies:(NSArray *)cookies { NSMutableDictionary* cookieDict = [NSMutableDictionary new]; for(NSHTTPCookie* cookie in cookies){ [cookieDict setValue:cookie.properties forKey:cookie.name]; } //쿠키 설정 NSHTTPCookie *localCookie = [NSHTTPCookie cookieWithProperties:cookieDict]; [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:localCookie]; } #pragma mark - Singleton + (RequestHandler *)handler { static RequestHandler *sharedRequestHandler = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedRequestHandler = [[self alloc] init]; }); return sharedRequestHandler; } - (id)init { if (self = [super init]) { } return self; } @end