3

如何将键值对添加到 NSMutableURLRequest 的正文中?我知道我可以使用这样的东西:

NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:8080/upload/"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
NSString *bodyContents = @"fileName=";
[bodyContents stringByAppendingString:fileName];
[bodyContents stringByAppendingString:@"&"];
[bodyContents stringByAppendingString:@"deviceName="];
[bodyContents stringByAppendingString:deviceName];
[bodyContents stringByAppendingString:@"fileContents="];
[bodyContents stringByAppendingString:fileContents];

但这似乎很麻烦,尤其是当我到达需要在请求中提交大量值的地方时。我希望苹果能提供一种类似[request addBodyField:@"fileName":fileName]或同样有用的方法,但我无法在文档中找到。有没有我遗漏的,或者我应该坚持附加字符串?

4

5 回答 5

5

这里有很多很好的答案。这就是我所做的:我构建了一个参数类,它负责配对语法以及 url 编码。

#import "NSString+URLEncoding.h"

@interface UrlParameter ()

@property (strong, nonatomic) NSString *pair;
@property (strong, nonatomic) NSString *encodedPair;

@end

@implementation UrlParameter

@synthesize pair = _pair;
@synthesize encodedPair = _encodedPair;


+ (UrlParameter *)withName:(NSString *)name value:(NSString *)value {

    UrlParameter *answer = [[UrlParameter alloc] init];
    answer.pair = [NSString stringWithFormat:@"%@=%@", name, value];
    answer.encodedPair = [NSString stringWithFormat:@"%@=%@", [name urlEncode], [value urlEncode]];

    return answer;  // autorelease if non-ARC
}

@end

这依赖于我从几篇文章中拼凑出来的这个 NSString 类别方法。(也支持 ARC):

@implementation NSString (URLEncoding)

- (NSString *)urlEncodeUsingEncoding:(CFStringEncoding)encoding {

    return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                                                               (__bridge CFStringRef)self,
                                                               NULL,
                                                               CFSTR("!*'();:@&=+$,/?%#[]"),
                                                               encoding));
}

- (NSString *)urlEncode {
    return [self urlEncodeUsingEncoding:kCFStringEncodingUTF8];
}

@end

我还将 URL 请求子类化并为其提供可变参数数组,然后,在它开始之前,它会执行以下操作:

// in the interface
@property (strong, nonatomic) NSMutableArray *parameters;

- (void)prepareParameters {

    NSMutableString *encodedParameterPairs = [NSMutableString stringWithCapacity:256];

    int position = 1;
    for (UrlParameter *requestParameter in self.parameters) {
        [encodedParameterPairs appendString:[requestParameter encodedPair]];
        if (position < [self.parameters count]) [encodedParameterPairs appendString:@"&"];
        position++;
    }

    if ([[self HTTPMethod] isEqualToString:@"GET"] || [[self HTTPMethod] isEqualToString:@"DELETE"]) {

        NSString *urlString = [NSString stringWithFormat:@"%@?%@", [self URLString], encodedParameterPairs];
        [self setURL:[NSURL URLWithString:urlString]];

    } else {

        // POST, PUT
        NSData *postData = [encodedParameterPairs dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
        [self setHTTPBody:postData];
        [self setValue:[NSString stringWithFormat:@"%d", [postData length]] forHTTPHeaderField:@"Content-Length"];
        [self setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    }
}
于 2012-03-22T23:27:38.003 回答
5

问题是它stringByAppendingString不会就地修改字符串,而是返回一个包含结果的新字符串。但是,您没有将结果分配stringByAppendingString给任何变量,并且bodyContents保持不变。

要解决这个问题,您可以使用stringWithFormat

NSString *bodyContents = [NSString stringWithFormat:@"fileName=%@&deviceName=%@fileContents=%@", fileName, deviceName, fileContents];

或声明stringWithFormat为可变字符串并使用方法appendString

NSMutableString *bodyContents = @"fileName=";
[bodyContents appendString:fileName];
[bodyContents appendString:@"&"];
// ...

或在每次调用时分配stringWithFormatto的结果:bodyContents

NSString *bodyContents = @"fileName=";
bodyContents = [bodyContents stringByAppendingString:fileName];
bodyContents = [bodyContents stringByAppendingString:@"&"];
// ...
于 2012-03-22T21:57:16.007 回答
3

我推荐 +stringWithFormat。

编辑:像这样:

NSURL *url = [[NSURL alloc] initWithString:@"http://localhost:8080/upload/"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
NSString *bodyContents = [NSString stringWithFormat:@"fileName=%@%@%@%@%@%@",fileName, @"&",@"deviceName=",deviceName,@"fileContents=",fileContents];

我不必使用任何 NSMutableRequests,但如果您需要字符串文字(\n 表示换行符 \t 表示制表符)或标点符号,只需将它们放在每个 %@ 之间的必要位置。

于 2012-03-22T21:52:43.733 回答
1

简而言之。创建字符串:

NSString *bodyString = [NSString stringWithFormat:@"fileName=%@&deviceName=%@&fileContents=@%", fileName, deviceName, fileContents];

格式化为 NSData:

NSData *body = [bodyString dataUsingEncoding:NSUTF8StringEncoding];

添加正文以请求:

[request setHTTPBody:body];

注意:的格式bodyString取决于您的请求的 POST 格式:application/x-www-form-urlencodedmultipart/form-data. 如果您使用multipart/form-data- 服务器可能无法接受这种格式。

于 2012-03-22T22:25:15.687 回答
0

我相当肯定你必须使用一个字符串。

顺便说一句,你的字符串不是 NSMutableString,所以这些stringByAppendingString:方法实际上不会做任何事情,除非你也有bodyContents = [bodyContents string...

stringWithFormat是最好的方法:

NSString *bodyContents = [NSString stringWithFormat:@"fileName:%@&deviceName=%@&fileContents=%@", fileName, deviceName, fileContents"];

或者,您可以拥有一个键的 NSArray 和一个基于该键的 NSDictionary(保存值)。然后简单地循环遍历 NSArray 并创建字符串。

于 2012-03-22T21:56:45.850 回答