之前发布了一条关于JSON解析无法正常工作的查询。使用数据包嗅探器和另一个正常工作的客户端进行了更多调查,发现它是一种语法问题,我似乎无法解决这个问题。
底部的代码使HTTP请求中包含JSON: {" key":" value"}
我的服务器实际上是在寻找以下语法的JSON: key =%22value%22
我尝试编写一些手动执行此操作的代码,但我认为iOS必须有一些开箱即用的功能,而且我不希望将来出现故障。
我试图找到合适的代码来解决这个问题,但是不能(你可以看到我试过注释掉的一些代码)。谁能帮我?
+ (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;
}
}
答案 0 :(得分:1)
你说:
发生的事情是服务器期望的每个参数的内容实际上是JSON,但是每个参数都是单独发送的
如果您说您正在发布标准application/x-www-form-urlencoded
,但想要对值进行JSON编码,这有点不寻常(我要么专门使用JSON或x-www-form-urlencoded
,而不是结合它们),但这并不难。如您的示例所示,关键问题是您必须百分比转义生成的JSON。例如:
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
:
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
调用,其定义如下:
/** 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:@"+"];
}