向NSMutableURLRequest添加字段

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]这样有用的方法,但是我在文档中没有找到这样的方法。我是否遗漏了某个方法或者应该继续使用字符串拼接呢?

5个回答

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:@"&"];
// ...

或者在每次调用时将 stringWithFormat 的结果赋值给 bodyContents

NSString *bodyContents = @"fileName=";
bodyContents = [bodyContents stringByAppendingString:fileName];
bodyContents = [bodyContents stringByAppendingString:@"&"];
// ...

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"];
    }
}

我最终做的也基本上是这样。 - nick

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表示制表符)或标点符号,只需在每个%@之间必要的地方加入即可。


我会说 [request setValue:@"string" forHTTPHeaderField:@"string"];,但我认为这不是您想要实现的目标... - CodaFi
@CodaFi - 你可以进一步简化这行代码 NSString *bodyContents = [NSString stringWithFormat...,因为实际上只有三个参数。请看我的回答。 - sch

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,则该格式可能不被服务器接受。


0

我相当确定你需要使用字符串。

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

stringWithFormat是最好的方法:

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接