POST multipart/form-data with Objective-C(使用 Objective-C 发布多部分/表单数据)
问题描述
所以这个 HTML 代码为我提交了正确格式的数据.
So this HTML code submits the data in the correct format for me.
<form action="https://www.example.com/register.php" method="post" enctype="multipart/form-data">
Name: <input type="text" name="userName"><BR />
Email: <input type="text" name="userEmail"><BR />
Password: <input type="text" name="userPassword"><BR />
Avatar: <input type="file" name="avatar"><BR />
<input type="submit">
</form>
我查看了大量关于如何在 iOS 上执行多部分/表单数据 POST 的文章,但没有一个真正解释如果有正常参数以及文件上传该怎么做.
I've looked into a good number of articles on how to do a multipart/form-data POST on iOS, but none really explain what to do if there were normal parameters as well as the file upload.
能否请您帮我提供在 Obj-C 中发布此内容的代码?
Could you please help me with the code to POST this in Obj-C?
谢谢!
推荐答案
流程如下:
使用
userName、userEmail和userPassword参数创建字典.
Create dictionary with the
userName,userEmail, anduserPasswordparameters.
NSDictionary *params = @{@"userName" : @"rob",
@"userEmail" : @"rob@email.com",
@"userPassword" : @"password"};
确定图片的路径:
Determine the path for the image:
NSString *path = [[NSBundle mainBundle] pathForResource:@"avatar" ofType:@"png"];
创建请求:
Create the request:
NSString *boundary = [self generateBoundaryString];
// configure the request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
// set content type
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
[request setValue:contentType forHTTPHeaderField: @"Content-Type"];
// create body
NSData *httpBody = [self createBodyWithBoundary:boundary parameters:params paths:@[path] fieldName:fieldName];
这是上面用来构建请求正文的方法:
This is the method used above to build the body of the request:
- (NSData *)createBodyWithBoundary:(NSString *)boundary
parameters:(NSDictionary *)parameters
paths:(NSArray *)paths
fieldName:(NSString *)fieldName {
NSMutableData *httpBody = [NSMutableData data];
// add params (all params are strings)
[parameters enumerateKeysAndObjectsUsingBlock:^(NSString *parameterKey, NSString *parameterValue, BOOL *stop) {
[httpBody appendData:[[NSString stringWithFormat:@"--%@
", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"
", parameterKey] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"%@
", parameterValue] dataUsingEncoding:NSUTF8StringEncoding]];
}];
// add image data
for (NSString *path in paths) {
NSString *filename = [path lastPathComponent];
NSData *data = [NSData dataWithContentsOfFile:path];
NSString *mimetype = [self mimeTypeForPath:path];
[httpBody appendData:[[NSString stringWithFormat:@"--%@
", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="%@"
", fieldName, filename] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:[[NSString stringWithFormat:@"Content-Type: %@
", mimetype] dataUsingEncoding:NSUTF8StringEncoding]];
[httpBody appendData:data];
[httpBody appendData:[@"
" dataUsingEncoding:NSUTF8StringEncoding]];
}
[httpBody appendData:[[NSString stringWithFormat:@"--%@--
", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
return httpBody;
}
以上使用了以下实用方法:
The above uses the following utility methods:
@import MobileCoreServices; // only needed in iOS
- (NSString *)mimeTypeForPath:(NSString *)path {
// get a mime type for an extension using MobileCoreServices.framework
CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
assert(UTI != NULL);
NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));
assert(mimetype != NULL);
CFRelease(UTI);
return mimetype;
}
- (NSString *)generateBoundaryString {
return [NSString stringWithFormat:@"Boundary-%@", [[NSUUID UUID] UUIDString]];
}
然后提交请求.这里有很多很多的选择.
Then submit the request. There are many, many options here.
例如,如果使用NSURLSession,你可以创建NSURLSessionUploadTask:
For example, if using NSURLSession, you could create NSURLSessionUploadTask:
NSURLSession *session = [NSURLSession sharedSession]; // use sharedSession or create your own
NSURLSessionTask *task = [session uploadTaskWithRequest:request fromData:httpBody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error = %@", error);
return;
}
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"result = %@", result);
}];
[task resume];
或者你可以创建一个NSURLSessionDataTask:
request.HTTPBody = httpBody;
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"error = %@", error);
return;
}
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"result = %@", result);
}];
[task resume];
以上假设服务器只是返回文本响应.如果服务器返回 JSON 会更好,在这种情况下,您将使用 NSJSONSerialization 而不是 NSString 方法 initWithData.
The above assumes that the server is just returning text response. It's better if the server returned JSON, in which case you'd use NSJSONSerialization rather than NSString method initWithData.
同样,我正在使用上面 NSURLSession 的完成块再现,但也可以随意使用更丰富的基于委托的再现.但这似乎超出了这个问题的范围,所以我将把它留给你.
Likewise, I'm using the completion block renditions of NSURLSession above, but feel free to use the richer delegate-based renditions, too. But that seems beyond the scope of this question, so I'll leave that to you.
但希望这能说明这个想法.
But hopefully this illustrates the idea.
如果我没有指出那我会失职,比上面容易得多,你可以使用 AFNetworking,重复上面的步骤 1 和 2,然后只是调用:
I'd be remiss if I didn't point that, much easier than the above, you can use AFNetworking, repeating steps 1 and 2 above, but then just calling:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // only needed if the server is not returning JSON; if web service returns JSON, remove this line
NSURLSessionTask *task = [manager POST:urlString parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
NSError *error;
if (![formData appendPartWithFileURL:[NSURL fileURLWithPath:path] name:@"avatar" fileName:[path lastPathComponent] mimeType:@"image/png" error:&error]) {
NSLog(@"error appending part: %@", error);
}
} progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionTask *task, NSError *error) {
NSLog(@"error = %@", error);
}];
if (!task) {
NSLog(@"Creation of task failed.");
}
这篇关于使用 Objective-C 发布多部分/表单数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用 Objective-C 发布多部分/表单数据
- Android viewpager检测滑动超出范围 2022-01-01
- 如何检查发送到 Android 应用程序的 Firebase 消息的传递状态? 2022-01-01
- MalformedJsonException:在第1行第1列路径中使用JsonReader.setLenient(True)接受格式错误的JSON 2022-01-01
- 使用自定义动画时在 iOS9 上忽略 edgesForExtendedLayout 2022-01-01
- android 4中的android RadioButton问题 2022-01-01
- 想使用ViewPager,无法识别android.support.*? 2022-01-01
- Android - 拆分 Drawable 2022-01-01
- 用 Swift 实现 UITextFieldDelegate 2022-01-01
- Android - 我如何找出用户有多少未读电子邮件? 2022-01-01
- 在测试浓缩咖啡时,Android设备不会在屏幕上启动活动 2022-01-01
