为了实现POST请求,我们写一个NSMutableURLRequest的子类,XYFormEncodedPOSTRequest,他支持POST方式中用到的参数字典。
XYFormEncodedPOSTRequest.h:
#import@interface XYFormEncodedPOSTRequest : NSMutableURLRequest+ (id)requestWithURL:(NSURL *)url formParameters:(NSDictionary *)params;- (id)initWithURL:(NSURL *)url formParameters:(NSDictionary *)params;- (void)setFormParameters:(NSDictionary *)params;@end
XYFormEncodedPOSTRequest.m:
#import "XYFormEncodedPOSTRequest.h"#import "NSString+XYURLAdditions.h"@implementation XYFormEncodedPOSTRequest+ (id)requestWithURL:(NSURL *)url formParameters:(NSDictionary *)params{ return [[self alloc] initWithURL:url formParameters:params];}- (id)initWithURL:(NSURL *)url formParameters:(NSDictionary *)params{ if (self = [super initWithURL:url]) { [self setHTTPMethod:@"POST"]; [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [self setFormParameters:params]; } return self;}- (void)setFormParameters:(NSDictionary *)params{ NSStringEncoding enc = NSUTF8StringEncoding; NSMutableString *postBody = [NSMutableString string]; for (NSString *paramKey in params) { if ([paramKey length] > 0) { NSString *value = [params objectForKey:paramKey]; NSString *encodeValue = [value URLEncodedFormStringUsingEncoding:enc]; NSUInteger length = [postBody length]; NSString *paramFormat = (length == 0? @"%@=%@" : @"&%@=%@"); [postBody appendFormat:paramFormat, paramKey,encodeValue]; } } NSLog(@"postBody is now %@", postBody); [self setHTTPBody:[postBody dataUsingEncoding:enc]];}@end表单参数看上去和URL查询字符串差不多,但是要把它们放到http正文中,而不是加到URL中,所以,假如提交包含名字和年龄的表单,编写好的正文字符长因该向下面这样:name-Lucas+Drance&age=1.5. 每个参数的名字与值之间用等号(=)连接,然后把这些参数用and(&)连接起来。
因此,若给定一组名称值对,我们的cocoa代码需要像先前说明的那样把它们连接在一块,这就是-setFormetters:所做的事情,他是用NSString的扩展来处理所有的字符转义。
标准的-[NSString stringByAddingPercentEscapesUsingEncoding:]方法可以把接受器转换成合法的URL字符串。但是如果用户输入中包含了保留字符(+,&,=),他会不做任何处理。我们需要自己转义。
NSString+XYURLAdditions.h:#import如果先替换空白字符,那么转义处理将对所有加号做转义;我们只是想对用户输入做转义,所以在最后一步替换空白字符。 NSString+XYURLAdditions.m:@interface NSString (XYURLAdditions)- (NSString *)URLEncodedFormStringUsingEncoding:(NSStringEncoding)enc;- (NSString *)percentEscapedStringWithEncoding:(NSStringEncoding)enc additionalCharacters:(NSString *)add ignoredCharacters:(NSString *)ignore;@end
#import "NSString+XYURLAdditions.h"@implementation NSString (XYURLAdditions)- (NSString *)URLEncodedFormStringUsingEncoding:(NSStringEncoding)enc{ NSString *escapedStringWithSpaces = [self percentEscapedStringWithEncoding:enc additionalCharacters:@"&=+" ignoredCharacters:nil]; return escapedStringWithSpaces;}- (NSString *)percentEscapedStringWithEncoding:(NSStringEncoding)enc additionalCharacters:(NSString *)add ignoredCharacters:(NSString *)ignore{ CFStringEncoding convertedEncoding = CFStringConvertNSStringEncodingToEncoding(enc); return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)self, (CFStringRef)ignore, (CFStringRef)add, convertedEncoding));}@end字符串转换由第二个方法完成,他有两组字符参数:一组是该被转义的(即保留字符),一组是不应该转义的。使用Core Fundation中CFURLCreateStringByAddingPercentEscpes的调用会执行所需的特殊替换。
源代码: