最新消息:20190717 VPS服务器:Vultr新加坡,WordPress主题:大前端D8,统一介绍入口:关于

[已解决]Alamofire中multipartFormData中的name和filename到底应该是什么值

iOS crifan 1665浏览 0评论

折腾用Alamofire去上传文件时,发现有两个参数:

name

filename

            Alamofire.upload(
                .POST,
                ServerApi.uploadFileUrl(gCurUserItem.id),
                headers: curHeader,
                multipartFormData: {multipartFormData in
                    multipartFormData.appendBodyPart(
                        data: imageData,
                        name: “file”,
                        fileName: “image.jpg”,
                        mimeType: “image/jpeg”
                    )
                },

这里到底该传入什么值,不清楚。

要去搞清楚。

multipartForm Data name filename

HTTP协议之multipart/form-data请求分析 – 像风一样的自由 – 博客频道 – CSDN.NET

multipart form-data boundary 说明 – yefeng – ITeye技术网站

通过 http 协议上传文件(rfc1867协议概述) multipart/form-data;boundary 解释 – HTML/HTML5 – 天空小小岛技术论坛 – Powered by Discuz!

<div–<—————————40612316912668
Content-Disposition: form-data; name=”c”; filename=”11 – 副本.txt”
Content-Type: text/plain
aaaa
abbb
cdd
ccc

<div–<—————————40612316912668

Content-Disposition: form-data; name=”d”; filename=”11.txt”
Content-Type: text/plain

Multipart/form-data – 简书

Content-Disposition: form-data; name=”imageName”; filename=”imageName.png”  
Content-Type: image/png

Under the hood: An HTTP request with multipart/form-data « Huy Nguyen

html – Example of multipart/form-data – Stack Overflow

请问如何用nodejs通过post发送multipart/form-data类型的http请求? – CNode技术社区

->

好像是:

name是针对于多个文件的时候才有用。

filename是当前文件名

-》那么估计是:

对于一次只上传单个文件的话,估计不用传递name了,只需要传递filename值应该就可以了。

-》

如果要传name的话,那么可以考虑写成:

name=“filenameNoSuffix”, filename=“fullFilename.suffix”

比如:

name=“20160625”,filename=“20160625.jpg”

后来再去看Alamofire的源码发现:

/**
    Constructs `multipart/form-data` for uploads within an HTTP or HTTPS body. There are currently two ways to encode 
    multipart form data. The first way is to encode the data directly in memory. This is very efficient, but can lead 
    to memory issues if the dataset is too large. The second way is designed for larger datasets and will write all the 
    data to a single file on disk with all the proper boundary segmentation. The second approach MUST be used for 
    larger datasets such as video content, otherwise your app may run out of memory when trying to encode the dataset.
    For more information on `multipart/form-data` in general, please refer to the RFC-2388 and RFC-2045 specs as well
    and the w3 form documentation.
    – https://www.ietf.org/rfc/rfc2388.txt
    – https://www.ietf.org/rfc/rfc2045.txt
    – https://www.w3.org/TR/html401/interact/forms.html#h-17.13
*/
public class MultipartFormData {
    /// The `Content-Type` header value containing the boundary used to generate the `multipart/form-data`.
    public var contentType: String { get }
    /// The content length of all body parts used to generate the `multipart/form-data` not including the boundaries.
    public var contentLength: UInt64 { get }
    /// The boundary used to separate the body parts in the encoded form data.
    public let boundary: String
    /**
            Creates a multipart form data object.
            – returns: The multipart form data object.
        */
    public init()
    /**
            Creates a body part from the data and appends it to the multipart form data object.
            The body part data will be encoded using the following format:
            – `Content-Disposition: form-data; name=#{name}` (HTTP Header)
            – Encoded data
            – Multipart form boundary
            – parameter data: The data to encode into the multipart form data.
            – parameter name: The name to associate with the data in the `Content-Disposition` HTTP header.
        */
    public func appendBodyPart(data data: NSData, name: String)
    /**
            Creates a body part from the data and appends it to the multipart form data object.
            The body part data will be encoded using the following format:
            – `Content-Disposition: form-data; name=#{name}` (HTTP Header)
            – `Content-Type: #{generated mimeType}` (HTTP Header)
            – Encoded data
            – Multipart form boundary
            – parameter data:     The data to encode into the multipart form data.
            – parameter name:     The name to associate with the data in the `Content-Disposition` HTTP header.
            – parameter mimeType: The MIME type to associate with the data content type in the `Content-Type` HTTP header.
        */
    public func appendBodyPart(data data: NSData, name: String, mimeType: String)
    /**
            Creates a body part from the data and appends it to the multipart form data object.
            The body part data will be encoded using the following format:
            – `Content-Disposition: form-data; name=#{name}; filename=#{filename}` (HTTP Header)
            – `Content-Type: #{mimeType}` (HTTP Header)
            – Encoded file data
            – Multipart form boundary
            – parameter data:     The data to encode into the multipart form data.
            – parameter name:     The name to associate with the data in the `Content-Disposition` HTTP header.
            – parameter fileName: The filename to associate with the data in the `Content-Disposition` HTTP header.
            – parameter mimeType: The MIME type to associate with the data in the `Content-Type` HTTP header.
        */
    public func appendBodyPart(data data: NSData, name: String, fileName: String, mimeType: String)
    /**
            Creates a body part from the file and appends it to the multipart form data object.
            The body part data will be encoded using the following format:
            – `Content-Disposition: form-data; name=#{name}; filename=#{generated filename}` (HTTP Header)
            – `Content-Type: #{generated mimeType}` (HTTP Header)
            – Encoded file data
            – Multipart form boundary
            The filename in the `Content-Disposition` HTTP header is generated from the last path component of the
            `fileURL`. The `Content-Type` HTTP header MIME type is generated by mapping the `fileURL` extension to the
            system associated MIME type.
            – parameter fileURL: The URL of the file whose content will be encoded into the multipart form data.
            – parameter name:    The name to associate with the file content in the `Content-Disposition` HTTP header.
        */
    public func appendBodyPart(fileURL fileURL: NSURL, name: String)

-》

很清楚了:

name和filename都应该传递

可以按照上述的总结,写成:

如果要传name的话,那么可以考虑写成:

name=“filenameNoSuffix”, filename=“fullFilename.suffix”

比如:

name=“20160625”,filename=“20160625.jpg”

然后,如果知道了文件的绝对路径,则可以用:

appendBodyPart(fileURL fileURL: NSURL, name: String)

其内部会自动帮你:

filename值为:文件路径中最后部分的文件名

根据文件路径最后的文件名的后缀,去计算出Content-Type的值

->后来经过调试,此处发现:

此处的name必须是”file”

然后filename可以指定别人值,比如”20160625_085958.jpg”

否则上传文件就出错:

             response=SUCCESS: {
                errors =     (
                    “The request body may not be null”,
                    “The request body may not be null”
                );
            }

估计是:

服务器上传的接口设计就是:

-》必须传递file这个值

-》但是也不太应该是:

通过name指定file吧?

先不管,最后,能工作的结果是:

    func uploadImageData(imageData:NSData){
        dispatchBackground_async({
            gLog.verbose(“imageData.length=\(imageData.length)”)
            self.pleaseWait()
            var curHeader = Dictionary<String, String>()
            curHeader[“authenticate”] = “token ” + gCurUserItem.accessToken
            gLog.verbose(“curHeader=\(curHeader)”)
    //        let attachmentFilename =  “image.jpg”
            let curDate = NSDate()
            /*
            let name = curDate.toString(“yyyyMMdd_hhmmss”)
            let filename = name + “.jpg”
            gLog.verbose(“name=\(name), filename=\(filename)”)
             ->
             response=SUCCESS: {
                errors =     (
                    “The request body may not be null”,
                    “The request body may not be null”
                );
            }
             */
            let name = “file”
            let filename = curDate.toString(“yyyyMMdd_hhmmss”) + “.jpg”
            gLog.verbose(“name=\(name), filename=\(filename)”)
            //uploadImageData > name=file, filename=20160625_085958.jpg
            Alamofire.upload(
                .POST,
                ServerApi.uploadFileUrl(gCurUserItem.id),
                headers: curHeader,
                multipartFormData: {multipartFormData in
                    multipartFormData.appendBodyPart(
                        data: imageData,
                        name: name,
                        fileName: filename,
                        mimeType: “image/jpeg”
                    )
                },
                encodingCompletion: { encodingResult in
                    gLog.verbose(“encodingResult=\(encodingResult)”)
                    /*
    encodingResult=Success($ curl -i \
        -X POST \
        -H “User-Agent: Sales App/com.qoro.QorosSalesApp (2016.6.24; OS ban ben 9.3(ban hao 13E230))” \
        -H “authenticate: token fmc2q2m25vre0htehsijmlur53” \
        -H “Content-Type: multipart/form-data; boundary=alamofire.boundary.5fd5efc56016a4df” \
        -H “Accept-Encoding: gzip;q=1.0, compress;q=0.5” \
        -H “Accept-Language: en-US;q=1.0, zh-Hans-US;q=0.9” \
        “http://192.168.1.102:8080/app/user/10000010/upload”, false, nil)
    encodingResult=Success($ curl -i \
        -X POST \
        -H “User-Agent: Sales App/com.qoro.QorosSalesApp (2016.6.24; OS ban ben 9.3(ban hao 13E230))” \
        -H “authenticate: token 4up3enr7nfd6c3rfei1ukcg1vv” \
        -H “Content-Type: multipart/form-data; boundary=alamofire.boundary.01fc8db6b551cd51” \
        -H “Accept-Encoding: gzip;q=1.0, compress;q=0.5” \
        -H “Accept-Language: en-US;q=1.0, zh-Hans-US;q=0.9” \
        “http://qapp.chinacloudapp.cn/app/user/10000010/upload”, false, nil)
                     */
                    switch encodingResult {
                    //case .Success(let uploadRequest, streamingFromDisk, streamFileURL):
                        case .Success(let uploadRequest, _, _):
//                        gLog.verbose(“uploadRequest=\(uploadRequest), streamingFromDisk=\(streamingFromDisk), streamFileURL=\(streamFileURL)”)
                            gLog.verbose(“uploadRequest=\(uploadRequest)”)
                        //upload=POST http://192.168.1.102:8080/app/user/10000010/upload
                        //uploadRequest=POST http://qapp.chinacloudapp.cn/app/user/10000010/upload
                        uploadRequest.responseJSON(completionHandler:
                            { response in
                                gLog.verbose(“response=\(response)”)
                                /*
                                 response=SUCCESS: {
                                    code = 200;
                                    data =     {
                                        created = 1466850689624;
                                        id = 1000001020160625103129624;
                                        location = “<null>”;
                                        name = “image.jpg”;
                                        owner = “<null>”;
                                        uploader = 10000010;
                                    };
                                    message = ok;
                                }
                                response=SUCCESS: {
                                    errors =     (
                                        “The request body may not be null”,
                                        “The request body may not be null”
                                    );
                                }
                                response=SUCCESS: {
                                    code = 200;
                                    data =     {
                                        created = 1466859610413;
                                        id = 1000001020160625130010413;
                                        location = “<null>”;
                                        name = “20160625_085958.jpg”;
                                        owner = “<null>”;
                                        uploader = 10000010;
                                    };
                                    message = ok;
                                }
                                 */
                                switch response.result {
                                case .Success(let value):
                                    let valueJson = JSON(value)
                                    gLog.verbose(“\(valueJson)”)
                                    /*
                                    {
                                      “message” : “ok”,
                                      “code” : 200,
                                      “data” : {
                                        “name” : “image.jpg”,
                                        “id” : “1000001020160625103129624”,
                                        “uploader” : 10000010,
                                        “location” : null,
                                        “created” : 1466850689624,
                                        “owner” : null
                                      }
                                    }
                                     */
                                    let statusCode = valueJson[“code”].int ?? 0
                                    if statusCode == 200 {
                                        let dataObj = valueJson[“data”].object
                                        let dataJson:JSON = JSON(dataObj)
                                        self.uploadAttachmentsHandler(Alamofire.Result.Success(dataJson))
                                        gLog.verbose(“dataJson=\(dataJson)”)
                                    } else {
                                        self.noticeError(“上传附件出错”, autoClear: true, autoClearTime: 1)
                                        let message = valueJson[“message”].string ?? “”
                                        let messageStrArr = message.splitToStrArr(“|”)
                                        var messageStr:String = message
                                        var subCode:Int = 0
                                        if messageStrArr.count > 1 {
                                            messageStr = messageStrArr[0]
                                            subCode = Int(messageStrArr[1]) ?? 0
                                        }
                                        let error:NSError = NSError(domain: HttpErrorDomain, code: statusCode, userInfo: [
                                            “message”   : messageStr,
                                            “code”      : statusCode,
                                            “subCode”   : subCode,
                                            ])
                                        self.uploadAttachmentsHandler(Alamofire.Result.Failure(error))
                                    }
                                case .Failure(let error):
                                    gLog.verbose(“error=\(error)”)
                                    self.uploadAttachmentsHandler(Alamofire.Result.Failure(error))
                                }
                        })
                    case .Failure(let encodingError):
                        gLog.error(“上传附件失败\(encodingError)”)
                    }
                }
            )
        })
    }

转载请注明:在路上 » [已解决]Alamofire中multipartFormData中的name和filename到底应该是什么值

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
62 queries in 0.236 seconds, using 18.88MB memory