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
, anduserPassword
parameters.
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 发布多部分/表单数据
基础教程推荐
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01