Jsonobject + 图像多部分 AFNetworking
Jsonobject + Image Multipart AFNetworking
我们正在尝试使用 AFNetworking 向服务器发送多部分请求。我们需要发送一个 json 对象和两个图像文件。以下是相同的 curl 请求。
curl -X POST http://localhost:8080/Circle/restapi/offer/add -H "Content-Type: multipart/form-data" -F "offerDTO={"code": null,"name": "Merry X'Mas - 1","remark": "25% discount on every purchase","validityDate": "22-12-2014","domainCode": "DO - 1","merchantCode": "M-4","isApproved": false,"discountValue": 25,"discountType": "PERCENTAGE"};type=application/json" -F "image=@Team Page.png;type=image/png" -F "letterhead=@Team Page.png;type=image/png"
我知道这应该相当容易,因为我已经实现了服务器以及 android 代码。我的朋友正在研究其中的 iOS 部分。我也在 google 上搜索了很多,但没有得到任何有用的东西。所以,我知道它违反了 Whosebug 的规则,但是你们能给我使用 AfNetworking 的相同代码吗?如果没有,请将我重定向到同一行的示例。
编辑:
请找到我们尝试过的以下代码:
UIImage *imageToPost = [UIImage imageNamed:@"1.png"];
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
offerDTO = [[NSMutableDictionary alloc]init];
[offerDTO setObject(angry)"" forKey:@"code"];
[offerDTO setObject:[NSString stringWithFormat:@"Testing"] forKey:@"discountDiscription"];
[offerDTO setObject:[NSString stringWithFormat:@"Test"] forKey:@"remark"];
[offerDTO setObject:@"07-05-2015" forKey:@"validityDate"];
[offerDTO setObject:@"C-7" forKey:@"creatorCode"];
[offerDTO setObject:@"M-1" forKey:@"merchantCode"];
[offerDTO setObject:[NSNumber numberWithBool:true] forKey:@"isApproved"];
[offerDTO setObject:@"2.4" forKey:@"discountValue"];
[offerDTO setObject:[NSString stringWithFormat:@"FREE"] forKey:@"discountType"];
NSURL *urlsss = [NSURL URLWithString:@"http://serverurl:8180"];
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:urlsss];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:@"POST"
path:@"/restapi/offer/add" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData)
{
NSData *myData = [NSJSONSerialization dataWithJSONObject:offerDTO
options:NSJSONWritingPrettyPrinted
error:NULL];
[formData appendPartWithFileData:imageData name:@"image"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFileData:imageData name:@"letterhead"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFormData:myData name:@"offerDTO"];
}
];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary *jsons = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:nil];
}
failure:^(AFHTTPRequestOperation operation, NSError error)
{
NSLog(@"error: %@", [operation error]);
}
];
一些观察:
您的示例是 AFNetworking 1.x。 AFNetworking 3.x 再现可能如下所示:
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"1" withExtension:@"png"];
// If you need to build dictionary dynamically as in your question, that's fine,
// but sometimes array literals are more concise way if the structure of
// the dictionary is always the same.
// Also note that these keys do _not_ match what are present in the `curl`
// so please double check these keys (e.g. `discountDiscription` vs
// `discountDescription` vs `name`)!
NSDictionary *offerDTO = @{@"code" : @"",
@"discountDescription" : @"Testing",
@"remark" : @"Test",
@"validityDate" : @"07-05-2015",
@"creatorCode" : @"C-7",
@"merchantCode" : @"M-1",
@"isApproved" : @YES,
@"discountValue" : @2.4,
@"discountType" : @"FREE"};
// `AFHTTPSessionManager` is AFNetworking 3.x equivalent to `AFHTTPClient` in AFNetworking 1.x
NSURL *baseURL = [NSURL URLWithString:@"http://serverurl:8180"];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL];
// The `POST` method both creates and issues the request
[manager POST:@"/restapi/offer/add" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
NSError *error;
BOOL success;
success = [formData appendPartWithFileURL:fileURL
name:@"image"
fileName:@"image.jpg"
mimeType:@"image/png"
error:&error];
NSAssert(success, @"Failure adding file: %@", error);
success = [formData appendPartWithFileURL:fileURL
name:@"letterhead"
fileName:@"image.jpg"
mimeType:@"image/png"
error:&error];
NSAssert(success, @"Failure adding file: %@", error);
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:offerDTO options:0 error:&error];
NSAssert(jsonData, @"Failure building JSON: %@", error);
// You could just do:
//
// [formData appendPartWithFormData:jsonData name:@"offerDTO"];
//
// but I now notice that in your `curl`, you set the `Content-Type` for the
// part, so if you want to do that, you could do it like so:
NSDictionary *jsonHeaders = @{@"Content-Disposition" : @"form-data; name=\"offerDTO\"",
@"Content-Type" : @"application/json"};
[formData appendPartWithHeaders:jsonHeaders body:jsonData];
} progress:^(NSProgress * _Nonnull uploadProgress) {
// do whatever you want here
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"error = %@", error);
}];
您正在此处创建操作,但从未将其添加到队列中以启动它。我假设你在其他地方这样做。值得注意的是,AFHTTPSessionManager
不支持像已弃用的 AFHTTPRequestOperationManager
或 AFHTTPClient
那样的操作。上面的代码只是自动开始运行。
注意,AFNetworking 现在假定响应为 JSON。鉴于您的代码表明响应是 JSON,请注意不需要 JSONObjectWithData
,因为已经为您完成了。
现在您的代码正在 (a) 创建 UIImage
; (b) 将其转换回 NSData
; (c) 将其添加到 formData
。由于多种原因,这是低效的:
具体来说,通过获取图像资产,将其加载到 UIImage
,然后使用 UIImageJPEGRepresentation
,您可能会使生成的 NSData
变得相当大比原始资产。您可能会考虑只获取原始资产,完全绕过 UIImage
,然后发送(显然,如果您要发送 PNG,那么也要更改 mime 类型)。
向请求添加NSData
的过程会导致更大的内存占用。通常,如果您提供一个文件名,它可以使峰值内存使用量保持在较低水平。
您可以将 NSdictionary 直接传递给 parametersfield
中的 manger post 块
UIImage *imageToPost = [UIImage imageNamed:@"1.png"];
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
NSDictionary *offerDTO = @{@"code" : @"",
@"discountDescription" : @"Testing",
@"remark" : @"Test",
@"validityDate" : @"07-05-2015",
@"creatorCode" : @"C-7",
@"merchantCode" : @"M-1",
@"isApproved" : @YES,
@"discountValue" : @2.4,
@"discountType" : @"FREE"};
NSURL *baseURL = [NSURL URLWithString:@"http://serverurl:8180"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];
[manager POST:@"/restapi/offer/add" parameters:offerDTO constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"image"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFileData:imageData name:@"letterhead"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithHeaders:jsonHeaders body:jsonData];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"responseObject = %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"error = %@", error);
}]
;
我们正在尝试使用 AFNetworking 向服务器发送多部分请求。我们需要发送一个 json 对象和两个图像文件。以下是相同的 curl 请求。
curl -X POST http://localhost:8080/Circle/restapi/offer/add -H "Content-Type: multipart/form-data" -F "offerDTO={"code": null,"name": "Merry X'Mas - 1","remark": "25% discount on every purchase","validityDate": "22-12-2014","domainCode": "DO - 1","merchantCode": "M-4","isApproved": false,"discountValue": 25,"discountType": "PERCENTAGE"};type=application/json" -F "image=@Team Page.png;type=image/png" -F "letterhead=@Team Page.png;type=image/png"
我知道这应该相当容易,因为我已经实现了服务器以及 android 代码。我的朋友正在研究其中的 iOS 部分。我也在 google 上搜索了很多,但没有得到任何有用的东西。所以,我知道它违反了 Whosebug 的规则,但是你们能给我使用 AfNetworking 的相同代码吗?如果没有,请将我重定向到同一行的示例。
编辑: 请找到我们尝试过的以下代码:
UIImage *imageToPost = [UIImage imageNamed:@"1.png"];
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
offerDTO = [[NSMutableDictionary alloc]init];
[offerDTO setObject(angry)"" forKey:@"code"];
[offerDTO setObject:[NSString stringWithFormat:@"Testing"] forKey:@"discountDiscription"];
[offerDTO setObject:[NSString stringWithFormat:@"Test"] forKey:@"remark"];
[offerDTO setObject:@"07-05-2015" forKey:@"validityDate"];
[offerDTO setObject:@"C-7" forKey:@"creatorCode"];
[offerDTO setObject:@"M-1" forKey:@"merchantCode"];
[offerDTO setObject:[NSNumber numberWithBool:true] forKey:@"isApproved"];
[offerDTO setObject:@"2.4" forKey:@"discountValue"];
[offerDTO setObject:[NSString stringWithFormat:@"FREE"] forKey:@"discountType"];
NSURL *urlsss = [NSURL URLWithString:@"http://serverurl:8180"];
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:urlsss];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:@"POST"
path:@"/restapi/offer/add" parameters:nil constructingBodyWithBlock: ^(id <AFMultipartFormData>formData)
{
NSData *myData = [NSJSONSerialization dataWithJSONObject:offerDTO
options:NSJSONWritingPrettyPrinted
error:NULL];
[formData appendPartWithFileData:imageData name:@"image"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFileData:imageData name:@"letterhead"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFormData:myData name:@"offerDTO"];
}
];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSDictionary *jsons = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:nil];
}
failure:^(AFHTTPRequestOperation operation, NSError error)
{
NSLog(@"error: %@", [operation error]);
}
];
一些观察:
您的示例是 AFNetworking 1.x。 AFNetworking 3.x 再现可能如下所示:
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"1" withExtension:@"png"]; // If you need to build dictionary dynamically as in your question, that's fine, // but sometimes array literals are more concise way if the structure of // the dictionary is always the same. // Also note that these keys do _not_ match what are present in the `curl` // so please double check these keys (e.g. `discountDiscription` vs // `discountDescription` vs `name`)! NSDictionary *offerDTO = @{@"code" : @"", @"discountDescription" : @"Testing", @"remark" : @"Test", @"validityDate" : @"07-05-2015", @"creatorCode" : @"C-7", @"merchantCode" : @"M-1", @"isApproved" : @YES, @"discountValue" : @2.4, @"discountType" : @"FREE"}; // `AFHTTPSessionManager` is AFNetworking 3.x equivalent to `AFHTTPClient` in AFNetworking 1.x NSURL *baseURL = [NSURL URLWithString:@"http://serverurl:8180"]; AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:baseURL]; // The `POST` method both creates and issues the request [manager POST:@"/restapi/offer/add" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) { NSError *error; BOOL success; success = [formData appendPartWithFileURL:fileURL name:@"image" fileName:@"image.jpg" mimeType:@"image/png" error:&error]; NSAssert(success, @"Failure adding file: %@", error); success = [formData appendPartWithFileURL:fileURL name:@"letterhead" fileName:@"image.jpg" mimeType:@"image/png" error:&error]; NSAssert(success, @"Failure adding file: %@", error); NSData *jsonData = [NSJSONSerialization dataWithJSONObject:offerDTO options:0 error:&error]; NSAssert(jsonData, @"Failure building JSON: %@", error); // You could just do: // // [formData appendPartWithFormData:jsonData name:@"offerDTO"]; // // but I now notice that in your `curl`, you set the `Content-Type` for the // part, so if you want to do that, you could do it like so: NSDictionary *jsonHeaders = @{@"Content-Disposition" : @"form-data; name=\"offerDTO\"", @"Content-Type" : @"application/json"}; [formData appendPartWithHeaders:jsonHeaders body:jsonData]; } progress:^(NSProgress * _Nonnull uploadProgress) { // do whatever you want here } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSLog(@"responseObject = %@", responseObject); } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { NSLog(@"error = %@", error); }];
您正在此处创建操作,但从未将其添加到队列中以启动它。我假设你在其他地方这样做。值得注意的是,
AFHTTPSessionManager
不支持像已弃用的AFHTTPRequestOperationManager
或AFHTTPClient
那样的操作。上面的代码只是自动开始运行。注意,AFNetworking 现在假定响应为 JSON。鉴于您的代码表明响应是 JSON,请注意不需要
JSONObjectWithData
,因为已经为您完成了。现在您的代码正在 (a) 创建
UIImage
; (b) 将其转换回NSData
; (c) 将其添加到formData
。由于多种原因,这是低效的:具体来说,通过获取图像资产,将其加载到
UIImage
,然后使用UIImageJPEGRepresentation
,您可能会使生成的NSData
变得相当大比原始资产。您可能会考虑只获取原始资产,完全绕过UIImage
,然后发送(显然,如果您要发送 PNG,那么也要更改 mime 类型)。向请求添加
NSData
的过程会导致更大的内存占用。通常,如果您提供一个文件名,它可以使峰值内存使用量保持在较低水平。
您可以将 NSdictionary 直接传递给 parametersfield
中的 manger post 块UIImage *imageToPost = [UIImage imageNamed:@"1.png"];
NSData *imageData = UIImageJPEGRepresentation(imageToPost, 1.0);
NSDictionary *offerDTO = @{@"code" : @"",
@"discountDescription" : @"Testing",
@"remark" : @"Test",
@"validityDate" : @"07-05-2015",
@"creatorCode" : @"C-7",
@"merchantCode" : @"M-1",
@"isApproved" : @YES,
@"discountValue" : @2.4,
@"discountType" : @"FREE"};
NSURL *baseURL = [NSURL URLWithString:@"http://serverurl:8180"];
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:baseURL];
[manager POST:@"/restapi/offer/add" parameters:offerDTO constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"image"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithFileData:imageData name:@"letterhead"
fileName:@"image.jpg"
mimeType:@"image/jpeg"];
[formData appendPartWithHeaders:jsonHeaders body:jsonData];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"responseObject = %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"error = %@", error);
}]
;