【问题标题】:Difference between multipart form upload and NSURLSession.uploadTaskWithRequest多部分表单上传和 NSURLSession.uploadTaskWithRequest 的区别
【发布时间】:2016-01-12 02:43:41
【问题描述】:

来自网络编程领域,我非常擅长处理多部分表单请求来上传文件。但是,在 iOS 中,我们有一个名为 NSURLSession 的东西,带有 uploadTaskWithRequest 方法,这似乎是调用图像上传之类的方法。

你能解释一下这两种方法的区别吗,多部分表单上传 vs uploadTaskWithRequest?如果我已经有一个处理多部分表单上传的后端,我可能需要进行哪些调整以使其也支持uploadTaskWithRequest

【问题讨论】:

    标签: ios multipartform-data nsurlsession


    【解决方案1】:

    幸运的是,在后台执行 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 类设置一个参数(在你创建请求之后):

    [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];
    

    【讨论】:

      【解决方案2】:

      使用multipart/form-data上传文件

      第一种使用 multipart/form-data 内容类型的方法最初是在 RFC 1867 中定义的,然后转移到万维网联盟,后者将其包含在 HTML 4.0 的规范中,其中表单以 HTML 表示,其中表单值通过 HTTP 和电子邮件发送。当用户填写表格时,表格被发送到服务器。这种技术被浏览器和网络服务器广泛支持和使用。

      不过,multipart/form-data 也可用于定义以 HTML 以外的其他表示形式呈现的表单数据。也就是说,您不一定需要 Web 浏览器或 Web 服务器。可被多种应用程序使用并由多种协议传输的当前规范是RFC 7578(来自 IETF)。

      但必须提到,multipart/form-data 内容类型并非总是/并非没有问题。它本身就相当复杂。此外,它使用/引用了许多其他 RFC,并且 - 作为清理的结果 - 它和它所依赖的那些已经被频繁地更改、过时和更新。由于其复杂性,序列化程序和解析器也变得相当复杂,并且存在很多错误和其他问题的空间。

      NSURLSession uploadTaskWithRequest

      NSURLSession 是如何组成请求的并没有准确记录。不过,它当然不使用 multipart/form-data 内容类型。

      对于上传任务,NSURLSession 使用带有 NSURLRequest 作为参数的 POST 请求,您可以自行设置该参数。也就是说,您可以选择设置内容类型(例如text/plain; charset=utf-8) 和其他标头。NSURLSession 也可以从给定内容(文件、流或 NSData)中派生出适当的内容类型。也就是说,我们可以说,就变成了一个“简单”的POST请求。由于复杂度较低,请求的麻烦也较少。

      因此,为了让您的服务器支持应上传文件的uploadTaskWithRequest,它应该只支持具有某种“简单”内容类型的 POST 请求。也就是说,与具有multipart/form-data 内容类型的“文件上传”相反,该内容类型在处置标头中包含文件名,服务器需要返回已写入资源(文件)的位置的URL .

      【讨论】:

        【解决方案3】:

        uploadTaskWithRequest 只是将NSData、文件或流作为请求的主体发送。除此之外,它不会做任何事情。它只是具有可以与后台会话一起使用的好处。

        因此,如果您的 Web 服务需要 multipart/form-data 请求,您必须自己构建该请求(除非您使用 AFNetworking 或 Alamofire 之类的工具来为您执行此操作)。构建该请求后,您可以使用dataTaskWithRequest(设置了NSMutableURLRequestHTTPBody)或uploadTaskWithRequest(在这种情况下您不设置HTTPBody,而是将其提供为uploadTaskWithRequest 的参数)。

        顺便说一句,Charles 这样的工具在这些情况下非常有用,可以让您观察幕后发生的事情。

        【讨论】:

        • Rob,我正在尝试使用 uploadTaskWithRequest 创建一个 multipart/form-data。如何提供 body 作为参数?
        • 您首先必须构建多部分主体(stackoverflow.com/a/26163136/1271826stackoverflow.com/a/24252378/1271826),然后将其作为data 参数提供给uploadTaskWithRequest。或者,如果您尝试使用后台会话(不允许NSData 再现)执行此操作,则将该多部分数据保存为文件,然后将该文件作为参数提供给uploadTaskWithRequest
        • 谢谢罗伯。我通过使用NSURLSessionDataTaskdataTaskWithRequest 方法解决了这个问题。 :)
        猜你喜欢
        • 1970-01-01
        • 2015-03-17
        • 1970-01-01
        • 2016-04-28
        • 1970-01-01
        • 1970-01-01
        • 2017-07-18
        • 2019-01-16
        • 2017-01-10
        相关资源
        最近更新 更多