今天遇到一个问题,图灵机器人平台的接口使用的是表单请求的方式,由于项目一开始是使用的iOS原生的NSURLSession,公司的项目一直都是使用的application/json的请求方式,一时之间很尴尬,因为很少使用multipart/form-data 表单方式请求;
接着用Postman 工具测了一下,请求是没有问题的,但是尝试把Postman提供的Objectve-C代码拷贝到iOS Demo上运行,但是并行不通,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
@"Content-Type": @"application/x-www-form-urlencoded",
@"cache-control": @"no-cache",
@"Postman-Token": @"e714247c-6bba-4e6a-9732-36a3672bcbba" };
NSArray *parameters = @[ @{ @"name": @"apiKey", @"value": @"1" },
@{ @"name": @"deviceId", @"value": @"123456789" },
@{ @"name": @"uid", @"value": @"10000" } ];
NSString *boundary = @"----WebKitFormBoundary7MA4YWxkTrZu0gW";

NSError *error;
NSMutableString *body = [NSMutableString string];
for (NSDictionary *param in parameters) {
[body appendFormat:@"--%@\r\n", boundary];
if (param[@"fileName"]) {
[body appendFormat:@"Content-Disposition:form-data; name=\"%@\"; filename=\"%@\"\r\n", param[@"name"], param[@"fileName"]];
[body appendFormat:@"Content-Type: %@\r\n\r\n", param[@"contentType"]];
[body appendFormat:@"%@", [NSString stringWithContentsOfFile:param[@"fileName"] encoding:NSUTF8StringEncoding error:&error]];
if (error) {
NSLog(@"%@", error);
}
} else {
[body appendFormat:@"Content-Disposition:form-data; name=\"%@\"\r\n\r\n", param[@"name"]];
[body appendFormat:@"%@", param[@"value"]];
}
}
[body appendFormat:@"\r\n--%@--\r\n", boundary];
NSData *postData = [body dataUsingEncoding:NSUTF8StringEncoding];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://iot-ai.tuling123.com/app-author/unbind"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];

在网上找了各种文章,结果都没有给整通,后来看到有的博客介绍了AFN上面对表单请求的支持,然后尝试了一下,先把代码贴出来,记录一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod:@"POST" URLString:URLString parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

NSArray *keys = [parameters allKeys];
for (id key in keys) { //拼接表单数据
[formData appendPartWithFormData:[parameters[key] dataUsingEncoding:NSUTF8StringEncoding] name:key];
}

} error:nil];


AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];

NSURLSessionUploadTask *uploadTask;
uploadTask = [manager uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
if (error) {
NSLog(@"Error: %@", error);
if (failure) {
failure(error);
}
} else {
NSLog(@"%@", responseObject);
if (success) {
success(responseObject);
}
}
}];

[uploadTask resume];