Created
May 16, 2018 13:15
-
-
Save jidolstar/00c2f5d03e26beec62b4f8e9a251d89c to your computer and use it in GitHub Desktop.
Objective-C HTTP 통신
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "bsHttpQueue.h" | |
#import "bsMacro.h" | |
#import "bsStr.h" | |
@interface bsHttpQueue(){ | |
NSString *_url; | |
NSDictionary *_param; | |
NSString *_method; | |
NSUInteger _timeout; | |
} | |
@end | |
@implementation bsHttpQueue | |
+(bsHttpQueue*)GWithUrl:(NSString*)url method:(NSString*)method param:(NSDictionary*)param timeout:(NSUInteger)timeout end:(bsCallback*)end{ | |
bsHttpQueue *queue = (bsHttpQueue*)[bsQueue GWithClassName:NSStringFromClass([self class]) end:end]; | |
[queue __setWithUrl:url method:method param:param timeout:timeout]; | |
return queue; | |
} | |
-(void)__setWithUrl:(NSString*)url method:(NSString*)method param:(NSDictionary*)param timeout:(NSUInteger)timeout { | |
_url = url; | |
_param = param; | |
_method = [[self class] __method:method]; | |
_timeout = timeout; | |
} | |
-(void)startWithData:(id*)data error:(bsError **)error{ | |
*data = [bsHttpQueue sendWithUrl:_url method:_method param:_param error:error timeout:_timeout]; | |
} | |
+(NSMutableDictionary*)__headerFromParam:(NSDictionary*)param{ //key의 첫글자가 @이면 header로 본다. | |
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init]; | |
if( param == nil || [param count] == 0 ) return dic; | |
[param enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL *stop) { | |
if( key.length > 1 && [[key substringToIndex:1] isEqualToString:@"@"] ) { | |
key = [key substringFromIndex:1]; | |
if( key.length == 0 ) return; | |
if( [obj isKindOfClass:[bsHttpFile class]] ) return; //@가 있더라도 파일이면 header가 될 수 없음! | |
if( [obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]] ) obj = [[bsStr sharedInstance] jsonDecode:obj]; | |
else if( ![obj isKindOfClass:[NSString class]] ) obj = [[bsStr sharedInstance] str:obj]; | |
[dic setObject:obj forKey:key]; | |
} | |
}]; | |
return dic; | |
} | |
+(NSMutableDictionary*)__dataFromParam:(NSDictionary*)param{ //key의 첫글자가 @가 아니면 data로 본다. | |
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init]; | |
if( param == nil || [param count] == 0 ) return dic; | |
[param enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL *stop) { | |
if( key.length > 0 && ![[key substringToIndex:1] isEqualToString:@"@"] ) { | |
if( [obj isKindOfClass:[bsHttpFile class]] ) return; | |
else if( [obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]] ) obj = [[bsStr sharedInstance] jsonDecode:obj]; | |
else if( ![obj isKindOfClass:[NSString class]] ) obj = [[bsStr sharedInstance] str:obj]; | |
[dic setObject:obj forKey:key]; | |
} | |
}]; | |
return dic; | |
} | |
+(NSMutableDictionary*)__fileFromParam:(NSDictionary*)param{ | |
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init]; | |
if( param == nil || [param count] == 0 ) return dic; | |
[param enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL *stop) { | |
if( [[key substringToIndex:1] isEqualToString:@"@"] ) return; //key에 @가 첫글자이면 무시함! | |
if( key.length == 0 ) return; | |
if( [obj isKindOfClass:[bsHttpFile class]] && [(bsHttpFile*)obj count] > 0 ){ | |
[dic setObject:obj forKey:key]; | |
} | |
}]; | |
return dic; | |
} | |
+(NSString*)__queryStringFromData:(NSDictionary*)data{ | |
if( data == nil || [data count] == 0 ) return @""; | |
NSMutableString *str = [[NSMutableString alloc] init]; | |
__block unsigned long i, j; | |
i = 0; | |
j = [data count]; | |
[data enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL *stop) { | |
[str appendString:[[bsStr sharedInstance] urlEncode:key]]; | |
[str appendString:@"="]; | |
[str appendString:[[bsStr sharedInstance] urlEncode:value]]; | |
if( i < j - 1 ) [str appendString:@"&"]; | |
i++; | |
}]; | |
return [NSString stringWithString:str]; | |
} | |
+(NSString*)__method:(NSString*)method{ | |
method = [method uppercaseString]; | |
if( [method isEqualToString:HTTP_METHOD_GET] || [method isEqualToString:HTTP_METHOD_POST] || [method isEqualToString:HTTP_METHOD_PUT] || [method isEqualToString:HTTP_METHOD_DELETE] ){ | |
return method; | |
} | |
bsException(@"http method는 GET, POST, PUT, DELETE중 하나이어야만 합니다."); | |
return nil; | |
} | |
+(NSData*)sendWithUrl:(NSString*)url method:(NSString*)method param:(NSDictionary*)param error:(bsError**)error timeout:(NSUInteger)timeout{ | |
if( timeout < 5 ) timeout = 5; | |
else if( timeout > 60 ) timeout = 60; | |
method = [self __method:method]; | |
@try { | |
NSDictionary *header = [self __headerFromParam:param]; | |
NSDictionary *data = [self __dataFromParam:param]; | |
NSDictionary *file = [self __fileFromParam:param]; | |
NSString *book = nil; | |
*error = nil; | |
if ( [method isEqualToString:HTTP_METHOD_GET] ) { | |
NSMutableString *str = [[NSMutableString alloc] init]; | |
if( [url rangeOfString:@"#"].length > 0 ) { | |
NSArray *urlMark = [[bsStr sharedInstance] split:url seperator:@"#" trim:YES]; | |
url = urlMark[0]; | |
book = urlMark[1]; | |
} | |
[str appendString:url]; | |
if( [url rangeOfString:@"?"].length > 0 ) [str appendString:@"&"]; | |
else [str appendString:@"?"]; | |
[str appendString:[self __queryStringFromData:data]]; | |
if( book != nil ) { | |
[str appendString:@"#"]; | |
[str appendString:book]; | |
} | |
url = [NSString stringWithString:str]; | |
data = nil; | |
} | |
if ( [method isEqualToString:HTTP_METHOD_GET] || [method isEqualToString:HTTP_METHOD_DELETE] ){ //(?)GET, DELETE 방식은 파일업로드 지원 안함 | |
file = nil; //GET은 File을 보낼 수 없음 | |
} | |
NSHTTPURLResponse *response = nil; | |
NSError *err = nil; | |
NSData *returnData; | |
NSMutableData *body = [NSMutableData data]; | |
NSMutableURLRequest *request = [NSMutableURLRequest | |
requestWithURL:[NSURL URLWithString:url] | |
cachePolicy:NSURLRequestReloadIgnoringCacheData | |
timeoutInterval:timeout]; | |
[request setHTTPMethod:method]; | |
[request setValue:@"Keep-Alive" forHTTPHeaderField:@"Connection"]; | |
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; //gzip 받아줌 | |
if( header && [header count] > 0 ){ //header셋팅 | |
[header enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL *stop) { | |
[request setValue:value forHTTPHeaderField:key]; | |
}]; | |
} | |
if( file && [file count] > 0 ) { //file이 있다면 파일처리하자. | |
NSString *BOUNDARY = @"-----------------bs-----"; | |
[request setValue:[NSString stringWithFormat:@"multipart/form-data, boundary=%@", BOUNDARY] forHTTPHeaderField:@"Content-Type"]; | |
NSData *crlf =[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *boundary = [[NSString stringWithFormat:@"--%@", BOUNDARY] dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *disp0 = [@"Content-Disposition: form-data; name=\"" dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *disp1 = [@"\"; filename=\"" dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *disp2 = [@"\"" dataUsingEncoding:NSUTF8StringEncoding]; | |
NSData *octet = [@"Content-Type: application/octet-stream" dataUsingEncoding:NSUTF8StringEncoding]; | |
if( data != nil ) { | |
[data enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL *stop) { | |
[body appendData:boundary]; | |
[body appendData:crlf]; | |
[body appendData:disp0]; | |
[body appendData:[key dataUsingEncoding:NSUTF8StringEncoding]]; | |
[body appendData:disp2]; | |
[body appendData:crlf]; | |
[body appendData:crlf]; | |
if( [obj isKindOfClass:[NSString class]] ) { | |
[body appendData:[obj dataUsingEncoding:NSUTF8StringEncoding]]; | |
} else { | |
[body appendData:[[[bsStr sharedInstance] str:obj] dataUsingEncoding:NSUTF8StringEncoding]]; | |
} | |
[body appendData:crlf]; | |
}]; | |
} | |
[file enumerateKeysAndObjectsUsingBlock:^(NSString *key, bsHttpFile *f, BOOL *stop) { | |
[f loop:^(NSString *name, NSData *data) { | |
[body appendData:boundary]; | |
[body appendData:crlf]; | |
[body appendData:disp0]; | |
[body appendData:[key dataUsingEncoding:NSUTF8StringEncoding]]; | |
[body appendData:disp1]; | |
[body appendData:[name dataUsingEncoding:NSUTF8StringEncoding]]; | |
[body appendData:disp2]; | |
[body appendData:crlf]; | |
[body appendData:octet]; | |
[body appendData:crlf]; | |
[body appendData:crlf]; | |
[body appendData:data]; | |
[body appendData:crlf]; | |
}]; | |
[bsHttpFile PUT:f]; //pool로 돌려줌 | |
}]; | |
[body appendData:boundary]; | |
[body appendData:[@"--" dataUsingEncoding:NSUTF8StringEncoding]]; | |
[body appendData:crlf]; | |
[body appendData:crlf]; | |
}else if( data && [data count] > 0 ){ | |
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; | |
[body appendData:[[self __queryStringFromData:data] dataUsingEncoding:NSUTF8StringEncoding]]; | |
} | |
[request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)[body length]] forHTTPHeaderField:@"Content-Length"]; | |
[request setHTTPBody:body]; | |
returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err]; | |
if ( err == nil ) { | |
return returnData; | |
} else { | |
*error = [bsError POPWithMsg:[NSString stringWithFormat:@"%@", err] data:err.userInfo func:__FUNCTION__ line:__LINE__]; | |
return nil; | |
} | |
} | |
@catch (NSException *e) { | |
*error = [bsError POPWithMsg:[NSString stringWithFormat:@"[%@]%@", [e name], [e reason]] data:[e userInfo] func:__FUNCTION__ line:__LINE__]; | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment