适用于iOS中HTTP POST请求的正确JSON编码 [英] Proper JSON encoding for HTTP POST request in iOS
问题描述
先前发布了有关JSON解析无法正常运行的查询.用数据包嗅探器以及另一个运行正常的客户端进行了更多调查,发现这是语法问题,我似乎仍然无法解决.
Posted a query previously about JSON parsing not working properly. Did more looking into it with a packet sniffer and also with another client that works properly and found out it's a syntax thing, that I still can't seem to solve.
底部的代码使HTTP请求中包含JSON,如下所示: {键":值"}
The code in the bottom makes the HTTP request to have the JSON in it as: {"key":"value"}
我的服务器实际上正在使用以下语法查找JSON: 键=%22value%22
And my server is actually looking for a JSON in the following syntax: key=%22value%22
我试图编写一些手动执行此操作的代码,但认为iOS必须有一些开箱即用的功能,而且我也不想在将来出现问题.
I tried to write some code that does this manually, but figured there must be something out of the box for iOS, and I don't want to have faults in the future.
我把它弄乱了一段时间,试图找到适合该工作的代码,但是没能(您可以看到一些我尝试将其注释掉的代码).谁能帮我?
I messed around with it for a while trying to find the right code for the job, but couldn't (you can see some code I tried commented out). Can anyone help me?
+ (NSString*)makePostCall:(NSString*)urlSuffix
keys:(NSArray*)keys
objects:(NSArray*)objects{
NSDictionary *params = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
// NSString *dataString = [self getDataStringFromDictionary:params];
// NSData *jsonData = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
options:0
error:&error];
// id jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:&error];
// NSLog(@"%@", jsonObject);
if (!jsonData) {
// should not happen
NSError *error;
NSLog(@"Got an error parsing the parameters: %@", error);
return nil;
} else {
// NSString *jsonRequest = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
// NSLog(@"%@", jsonRequest);
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", urlPrefix, urlSuffix]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
// NSData *requestData = [jsonRequest dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
// [request setValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody: jsonData];
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
// TODO: handle error somehow
NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return returnString;
}
}
推荐答案
您说的是
发生的事情是服务器期望的每个参数的内容实际上是JSON,但是每个参数都是单独发送的
what happens is that the content of each parameter the server expects is actually JSON, but each parameter is sent separately
如果您要发布的是标准application/x-www-form-urlencoded
,但想对值进行JSON编码,则这有点不寻常(我只使用JSON或x-www-form-urlencoded
,但不将它们组合在一起),但这并不难.如您的示例所示,关键问题是必须百分比转义所得的JSON.例如:
If you're saying that you're issuing a standard application/x-www-form-urlencoded
, but want to JSON encode the values, that's a little unusual (I'd either exclusively use JSON or x-www-form-urlencoded
, but not combine them), but it's not hard to do. The key issue, as shown in your example, is that you must percent escape the resulting JSON. For example:
NSURL *url = [NSURL URLWithString:kURLString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
// information to be encoded for first parameter
NSDictionary *value1 = @{@"name" : @"Dwayne Johnson",
@"age" : @41,
@"sex" : @"male"};
NSError *error;
NSData *json1 = [NSJSONSerialization dataWithJSONObject:value1 options:0 error:&error];
NSAssert(json1, @"Unable to create JSON for value1: %@", error);
// information to be encoded for second parameter
NSDictionary *value2 = @{@"name" : @"Lauren Hashian",
@"age" : @29,
@"sex" : @"female"};
NSData *json2 = [NSJSONSerialization dataWithJSONObject:value2 options:0 error:&error];
NSAssert(json2, @"Unable to create JSON for value1: %@", error);
// combine these parameters into single dictionary
NSDictionary *parameters = @{@"person" : json1, @"partner" : json2};
NSData *requestData = [self encodePostParameters:parameters];
[request setHTTPBody:requestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (!data) {
NSLog(@"sendAsynchronousRequest failed: %@", connectionError);
return;
}
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
// you can now use that `responseString` variable (but do this here,
// inside this completion block!)
}];
这将导致对以下内容的请求HTTPBody
:
That will result in a request HTTPBody
of:
person=%7B%22age%22%3A41%2C%22name%22%3A%22Dwayne+Johnson%22%2C%22sex%22%3A%22male%22%7D&partner=%7B%22age%22%3A29%2C%22name%22%3A%22Lauren+Hashian%22%2C%22sex%22%3A%22female%22%7D
这里有趣的逻辑是转义百分比,我在称为percentEscapeString
的方法中进行了转义,该方法从encodePostParameters
调用,定义如下:
The interesting logic here is the percent escaping, which I do in method called percentEscapeString
, which I call from encodePostParameters
, which is defined as follows:
/** Percent escape the post parameters for x-www-form-urlencoded request
*
* @param parameters A NSDictionary of the parameters to be encoded
*
* @return The NSData to be used in body of POST request (or URL or GET request)
*/
- (NSData *)encodePostParameters:(NSDictionary *)parameters
{
NSMutableArray *results = [NSMutableArray array];
for (NSString *key in parameters) {
NSString *string;
id value = parameters[key];
if ([value isKindOfClass:[NSData class]]) {
string = [[NSString alloc] initWithData:value encoding:NSUTF8StringEncoding];
} else if ([value isKindOfClass:[NSString class]]) {
string = value;
} else { // if you want to handle other data types, add that here
string = [value description];
}
[results addObject:[NSString stringWithFormat:@"%@=%@", key, [self percentEscapeString:string]]];
}
NSString *postString = [results componentsJoinedByString:@"&"];
return [postString dataUsingEncoding:NSUTF8StringEncoding];
}
/** Percent escape string
*
* Note, this does not use `stringByAddingPercentEscapesUsingEncoding`, because
* that that will not percent escape some critical reserved characters (notably
* `&` and `+`). This uses `CFURLCreateStringByAddingPercentEscapes`, instead.
*/
- (NSString *)percentEscapeString:(NSString *)string
{
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
(CFStringRef)@" ",
(CFStringRef)@":/?@!$&'()*+,;=",
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:@" " withString:@"+"];
}
这篇关于适用于iOS中HTTP POST请求的正确JSON编码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!