多部分表单上传和 NSURLSession.uploadTaskWithRequest 之间的区别
Difference between multipart form upload and NSURLSession.uploadTaskWithRequest
来自网络编程领域,我非常擅长使用多部分表单请求来上传文件。但是,在iOS中,我们有一个叫做NSURLSession
的东西,方法是uploadTaskWithRequest
,这似乎是调用图片上传之类的方法。
您能解释一下这两种方法的区别吗,多部分表单上传 vs uploadTaskWithRequest
?如果我已经有一个处理多部分表单上传的后端,我可能需要进行什么样的调整才能使其也支持 uploadTaskWithRequest
?
文件上传 multipart/form-data
第一种使用 multipart/form-data
Content-type 的方法最初是在 RFC 1867, then moved to the World Wide Web Consortium, which included it in the specification for HTML 4.0 中定义的,其中表单以 HTML 表示,表单值通过 HTTP 和电子方式发送邮件。当用户填写表单后,表单将发送到服务器。此技术得到浏览器和 Web 服务器的广泛支持和使用。
但是 multipart/form-data
也可用于定义以 HTML 以外的其他表示形式呈现的表单数据。也就是说,您不一定需要 Web 浏览器或 Web 服务器。可被多种应用程序使用并由多种协议传输的当前规范是 RFC 7578(来自 IETF)。
但必须提到的是,multipart/form-data
内容类型并非 always/is 并非没有问题。它本身就相当复杂。此外,它 uses/refers 到许多其他 RFC,并且 - 作为清理的结果 - 它和它所依赖的那些已经被频繁地更改、废弃和更新。由于其复杂性,序列化器和解析器也变得相当复杂,并且存在很多错误和其他问题的空间。
NSURLSession uploadTaskWithRequest
如何 NSURLSession
撰写请求未被准确记录。不过,它肯定不使用 multipart/form-data
内容类型。
对于上传任务,NSURLSession
使用带有 NSURLRequest
的 POST 请求作为您可以自行设置的参数。也就是说,您可以选择设置内容类型(例如 text/plain; charset=utf-8)
,以及其他 header。NSURLSession
也可以从给定的内容(文件、流或NSData)。也就是说,我们可以说,它变成了一个“简单”的POST请求。由于复杂度较低,请求也不那么麻烦。
因此,为了让您的服务器支持应上传文件的 uploadTaskWithRequest
,它应该只支持带有一些“简单”内容类型的 POST 请求。也就是说,与 multipart/form-data
内容类型的“文件上传”相反,其中包含配置 header 中的文件名,服务器需要 return URL写入资源(文件)的位置。
uploadTaskWithRequest
只是发送 NSData
、文件或流作为请求的主体。除此之外它什么都不做。它的好处就是可以与后台会话一起使用。
因此,如果您的 Web 服务需要 multipart/form-data
请求,则您必须自己构建该请求(除非您使用 AFNetworking 或 Alamofire 之类的工具来为您执行此操作)。构建该请求后,您可以使用 dataTaskWithRequest
(已设置 NSMutableURLRequest
的 HTTPBody
)或 uploadTaskWithRequest
(在这种情况下您不设置 HTTPBody
,而是将其作为参数提供给 uploadTaskWithRequest
).
顺便说一下,像 Charles 这样的工具在这些情况下非常有用,可以让您观察幕后发生的事情。
幸运的是,在后台执行 multipart/form-data POST 请求非常容易,例如,如果您想要上传图像和其他一些信息。
首先,以与创建同步请求相同的方式创建 NSMutableURLRequest(参见示例 POST multipart/form-data with Objective-C)。
然后,将请求的主体写入文件并将其提供给您使用 backgroundSessionConfiguration 创建的 NSURLSession 的 uploadTaskWithRequest 方法:
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(
NSCachesDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:imageUUID];
[request.HTTPBody writeToFile:filePath atomically:YES];
NSURLSessionUploadTask *task = [urlSession uploadTaskWithRequest:request
fromFile:[NSURL fileURLWithPath:filePath]];
[task resume];
如果您有多个任务并且希望能够在委托回调中区分它们,您可以使用 NSURLProtocol class 设置一个参数(在您创建请求之后):
[NSURLProtocol setProperty:imageUUID
forKey:@"yourKeyForTheImageUUID"
inRequest:request];
然后像这样在回调中取回它:
- (void)URLSession:(NSURLSession *)session
task:(nonnull NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
NSString *imageUUID = [NSURLProtocol propertyForKey:@"yourKeyForTheImageUUID"
inRequest:task.originalRequest];
来自网络编程领域,我非常擅长使用多部分表单请求来上传文件。但是,在iOS中,我们有一个叫做NSURLSession
的东西,方法是uploadTaskWithRequest
,这似乎是调用图片上传之类的方法。
您能解释一下这两种方法的区别吗,多部分表单上传 vs uploadTaskWithRequest
?如果我已经有一个处理多部分表单上传的后端,我可能需要进行什么样的调整才能使其也支持 uploadTaskWithRequest
?
文件上传 multipart/form-data
第一种使用 multipart/form-data
Content-type 的方法最初是在 RFC 1867, then moved to the World Wide Web Consortium, which included it in the specification for HTML 4.0 中定义的,其中表单以 HTML 表示,表单值通过 HTTP 和电子方式发送邮件。当用户填写表单后,表单将发送到服务器。此技术得到浏览器和 Web 服务器的广泛支持和使用。
但是 multipart/form-data
也可用于定义以 HTML 以外的其他表示形式呈现的表单数据。也就是说,您不一定需要 Web 浏览器或 Web 服务器。可被多种应用程序使用并由多种协议传输的当前规范是 RFC 7578(来自 IETF)。
但必须提到的是,multipart/form-data
内容类型并非 always/is 并非没有问题。它本身就相当复杂。此外,它 uses/refers 到许多其他 RFC,并且 - 作为清理的结果 - 它和它所依赖的那些已经被频繁地更改、废弃和更新。由于其复杂性,序列化器和解析器也变得相当复杂,并且存在很多错误和其他问题的空间。
NSURLSession uploadTaskWithRequest
如何 NSURLSession
撰写请求未被准确记录。不过,它肯定不使用 multipart/form-data
内容类型。
对于上传任务,NSURLSession
使用带有 NSURLRequest
的 POST 请求作为您可以自行设置的参数。也就是说,您可以选择设置内容类型(例如 text/plain; charset=utf-8)
,以及其他 header。NSURLSession
也可以从给定的内容(文件、流或NSData)。也就是说,我们可以说,它变成了一个“简单”的POST请求。由于复杂度较低,请求也不那么麻烦。
因此,为了让您的服务器支持应上传文件的 uploadTaskWithRequest
,它应该只支持带有一些“简单”内容类型的 POST 请求。也就是说,与 multipart/form-data
内容类型的“文件上传”相反,其中包含配置 header 中的文件名,服务器需要 return URL写入资源(文件)的位置。
uploadTaskWithRequest
只是发送 NSData
、文件或流作为请求的主体。除此之外它什么都不做。它的好处就是可以与后台会话一起使用。
因此,如果您的 Web 服务需要 multipart/form-data
请求,则您必须自己构建该请求(除非您使用 AFNetworking 或 Alamofire 之类的工具来为您执行此操作)。构建该请求后,您可以使用 dataTaskWithRequest
(已设置 NSMutableURLRequest
的 HTTPBody
)或 uploadTaskWithRequest
(在这种情况下您不设置 HTTPBody
,而是将其作为参数提供给 uploadTaskWithRequest
).
顺便说一下,像 Charles 这样的工具在这些情况下非常有用,可以让您观察幕后发生的事情。
幸运的是,在后台执行 multipart/form-data POST 请求非常容易,例如,如果您想要上传图像和其他一些信息。
首先,以与创建同步请求相同的方式创建 NSMutableURLRequest(参见示例 POST multipart/form-data with Objective-C)。
然后,将请求的主体写入文件并将其提供给您使用 backgroundSessionConfiguration 创建的 NSURLSession 的 uploadTaskWithRequest 方法:
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(
NSCachesDirectory, NSUserDomainMask, YES) lastObject]
stringByAppendingPathComponent:imageUUID];
[request.HTTPBody writeToFile:filePath atomically:YES];
NSURLSessionUploadTask *task = [urlSession uploadTaskWithRequest:request
fromFile:[NSURL fileURLWithPath:filePath]];
[task resume];
如果您有多个任务并且希望能够在委托回调中区分它们,您可以使用 NSURLProtocol class 设置一个参数(在您创建请求之后):
[NSURLProtocol setProperty:imageUUID
forKey:@"yourKeyForTheImageUUID"
inRequest:request];
然后像这样在回调中取回它:
- (void)URLSession:(NSURLSession *)session
task:(nonnull NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
NSString *imageUUID = [NSURLProtocol propertyForKey:@"yourKeyForTheImageUUID"
inRequest:task.originalRequest];