为了实现POST请求,我们写一个NSMutableURLRequest的子类,XYFormEncodedPOSTRequest,他支持POST方式中用到的参数字典。
XYFormEncodedPOSTRequest.h:
#import <Foundation/Foundation.h>
@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 <Foundation/Foundation.h>
@interface NSString (XYURLAdditions)
- (NSString *)URLEncodedFormStringUsingEncoding:(NSStringEncoding)enc;
- (NSString *)percentEscapedStringWithEncoding:(NSStringEncoding)enc additionalCharacters:(NSString *)add ignoredCharacters:(NSString *)ignore;
@end
如果先替换空白字符,那么转义处理将对所有加号做转义;我们只是想对用户输入做转义,所以在最后一步替换空白字符。
NSString+XYURLAdditions.m:
#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的调用会执行所需的特殊替换。
源代码:连接地址