Alamofire多表單上傳失敗

問題描述:多表單上傳時,經(jīng)常性的失敗,而且失敗一次后面就會一值失敗。

項目用的是Alamofire處理的網(wǎng)絡請求。

通過抓包工具發(fā)現(xiàn),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)!
}

看這段代碼我們注意到一點,拼接成字符串的時候,是沒有順序的。該問題出現(xiàn)的原因就在這。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字段的內(nèi)容拼接到前面, 這樣每次上傳都會成功了。

  • 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數(shù)據(jù)會放到放在 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
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容