美文网首页
Alamofire多表单上传失败

Alamofire多表单上传失败

作者: Maji1 | 来源:发表于2020-08-10 16:44 被阅读0次

    问题描述:多表单上传时,经常性的失败,而且失败一次后面就会一值失败。

    项目用的是Alamofire处理的网络请求。

    通过抓包工具发现,Content-DispositionContent-Type的前面时上传会成功,顺序颠倒过来就会失败。

    接下来就去查找Alamofire的源码,在MultipartFormData.swift文件中:

    • bodyHeader信息:
    private func encodeHeaders(for bodyPart: BodyPart) -> Data { 
      var headerText = ""
      for (key, value) in bodyPart.headers {
        headerText += "\(key): \(value)\(EncodingCharacters.crlf)"
      }
      headerText += EncodingCharacters.crlf
      return headerText.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    }
    

    看这段代码我们注意到一点,拼接成字符串的时候,是没有顺序的。该问题出现的原因就在这。Content-Disposition字段拼接到Content-Type后面时表单上传就会失败,Content-Disposition字段拼接到最前面表单上传才会成功。

    个人认为这并不是前段的bug,因为 rfc标准 在这里是没有顺序要求的。

    为了解决问题,暂时做了下修改:

    private func encodeHeaders(for bodyPart: BodyPart) -> Data {
       var headerText = ""
       let contentDisposition = bodyPart.headers["Content-Disposition"] ?? ""
       headerText += "Content-Disposition: \(contentDisposition)\(EncodingCharacters.crlf)"
       for (key, value) in bodyPart.headers {
          if key == "Content-Disposition" { continue }
          headerText += "\(key): \(value)\(EncodingCharacters.crlf)"
       }
       headerText += EncodingCharacters.crlf
       return headerText.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    }
    

    这里每次先取出Content-Disposition字段的内容拼接到前面, 这样每次上传都会成功了。

    • bodyPart信息:
        private func encode(_ bodyPart: BodyPart) throws -> Data {
            var encoded = Data()
    
            let initialData = bodyPart.hasInitialBoundary ? initialBoundaryData() : encapsulatedBoundaryData()
            encoded.append(initialData)
    
            let headerData = encodeHeaders(for: bodyPart)
            encoded.append(headerData)
    
            let bodyStreamData = try encodeBodyStream(for: bodyPart)
            encoded.append(bodyStreamData)
    
            if bodyPart.hasFinalBoundary {
                encoded.append(finalBoundaryData())
            }
    
            return encoded
        }
    

    headerData数据会放到放在 bodyStreamData 前面。

    再来了解下bodyStream的编码:

        private func encodeBodyStream(for bodyPart: BodyPart) throws -> Data {
            let inputStream = bodyPart.bodyStream
            inputStream.open()
            defer { inputStream.close() }
    
            var encoded = Data()
    
            while inputStream.hasBytesAvailable {
                var buffer = [UInt8](repeating: 0, count: streamBufferSize)
                let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
    
                if let error = inputStream.streamError {
                    throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: error))
                }
    
                if bytesRead > 0 {
                    encoded.append(buffer, count: bytesRead)
                } else {
                    break
                }
            }
    
            return encoded
        }
    

    相关文章

      网友评论

          本文标题:Alamofire多表单上传失败

          本文链接:https://www.haomeiwen.com/subject/kvkgehtx.html