Добавить поля в NSMutableURLRequest - PullRequest
3 голосов
/ 23 марта 2012

Как бы я добавил пары ключ-значение в тело 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];

Но это кажется большой проблемой, особенно если я попадаю туда, где мне нужно отправить много значений в запросе. Я надеюсь, что Apple предоставит такой метод, как [request addBodyField:@"fileName":fileName] или что-то такое же полезное, но я не смог найти его в документации. Я скучаю по одному или мне нужно просто добавить строки?

Ответы [ 5 ]

5 голосов
/ 23 марта 2012

Здесь много хороших ответов.Вот что я делаю: я построил класс параметров, который заботится о синтаксисе сопряжения, а также о кодировке 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-ready):

@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"];
    }
}
5 голосов
/ 23 марта 2012

Проблема в том, что 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:@"&"];
// ...
3 голосов
/ 23 марта 2012

Я рекомендую + 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для табуляции) или знаки препинания, просто поместите их, где необходимо, между каждым% @.

1 голос
/ 23 марта 2012

В двух словах. Создать строку:

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-urlencoded или multipart/form-data.Если вы используете multipart/form-data - этот формат, возможно, не будет принят сервером.

0 голосов
/ 23 марта 2012

Я вполне уверен, что вам придется использовать строку.

Кстати, ваша строка не является NSMutableString, поэтому эти stringByAppendingString: методы на самом деле ничего не сделают, если вы тожеиметь bodyContents = [bodyContents string...

stringWithFormat - лучший способ:

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

В качестве альтернативы вы можете иметь NSArray ключей и NSDictionary (для хранения значений), который основан на том, чтоключ.Затем просто переберите NSArray и создайте строку.

...