我正在嘗試將影像上傳到彈簧后端。它應該在后臺作業,因此我只能使用session.uploadTask函式 我的問題是后端希望我設定Content-Type標題。一個關鍵部分是boundary在我的請求正文中相應地定義和使用它,但是我應該如何boundary在影像上設定我的?
我見過的大多數教程都使用該session.uploadData功能來執行此操作,當您想在后臺執行操作時,該功能不可用。在那里我可以簡單地將 附加boundary到資料。
總結一下:boundary上傳圖片時如何正確使用標題欄位uploadTask(with request: URLRequest, fromFile fileURL: URL)?
我從春天收到這個錯誤:
org.springframework.web.multipart.MultipartException: Current request is not a multipart request
我的代碼:
let boundary = UUID().uuidString
// A background upload task must specify a file
var imageURLRequest = URLRequest(url: uploadURL)
imageURLRequest.httpMethod = "Post"
imageURLRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let imageTask = URLBackgroundSession.shared.uploadTask(with: imageURLRequest, fromFile: URL(fileURLWithPath: imagePath))
imageTask.resume()
uj5u.com熱心網友回復:
在您找到的那些其他示例中(例如,在 Swift 中使用引數上傳影像),他們構建了一個Data符合格式正確的multipart/form-data請求并在請求正文中使用的請求。
你必須在這里做同樣的事情,除了不是構建一個Data,你將創建一個臨時檔案,將所有這些寫入該檔案,然后在你的uploadTask.
例如:
func uploadImage(from imageURL: URL, filePathKey: String, to uploadURL: URL) throws {
let boundary = UUID().uuidString
var imageURLRequest = URLRequest(url: uploadURL)
imageURLRequest.httpMethod = "POST"
imageURLRequest.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
let folder = URL(filePath: NSTemporaryDirectory()).appending(path: "uploads")
try FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
let fileURL = folder.appendingPathExtension(boundary)
guard let outputStream = OutputStream(url: fileURL, append: false) else {
throw OutputStream.OutputStreamError.unableToCreateFile(fileURL)
}
outputStream.open()
try outputStream.write("--\(boundary)\r\n")
try outputStream.write("Content-Disposition: form-data; name=\"\(filePathKey)\"; filename=\"\(imageURL.lastPathComponent)\"\r\n")
try outputStream.write("Content-Type: \(imageURL.mimeType)\r\n\r\n")
try outputStream.write(contentsOf: imageURL)
try outputStream.write("\r\n")
try outputStream.write("--\(boundary)--\r\n")
outputStream.close()
let imageTask = URLBackgroundSession.shared.uploadTask(with: imageURLRequest, fromFile: fileURL)
imageTask.resume()
}
您可能應該洗掉urlSession(_:task:didCompleteWithError:).
FWIW,上面使用以下擴展來簡化的生成OutputStream:
extension OutputStream {
enum OutputStreamError: Error {
case stringConversionFailure
case unableToCreateFile(URL)
case bufferFailure
case writeFailure
case readFailure
}
/// Write `String` to `OutputStream`
///
/// - parameter string: The `String` to write.
/// - parameter encoding: The `String.Encoding` to use when writing the string. This will default to `.utf8`.
/// - parameter allowLossyConversion: Whether to permit lossy conversion when writing the string. Defaults to `false`.
func write(_ string: String, encoding: String.Encoding = .utf8, allowLossyConversion: Bool = false) throws {
guard let data = string.data(using: encoding, allowLossyConversion: allowLossyConversion) else {
throw OutputStreamError.stringConversionFailure
}
try write(data)
}
/// Write `Data` to `OutputStream`
///
/// - parameter data: The `Data` to write.
func write(_ data: Data) throws {
try data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) throws in
guard var pointer = buffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
throw OutputStreamError.bufferFailure
}
var bytesRemaining = buffer.count
while bytesRemaining > 0 {
let bytesWritten = write(pointer, maxLength: bytesRemaining)
if bytesWritten < 0 {
throw OutputStreamError.writeFailure
}
bytesRemaining -= bytesWritten
pointer = bytesWritten
}
}
}
/// Write contents of local `URL` to `OutputStream`
///
/// - parameter fileURL: The `URL` of the file to written to this output stream.
func write(contentsOf fileURL: URL) throws {
guard let inputStream = InputStream(url: fileURL) else {
throw OutputStreamError.readFailure
}
inputStream.open()
let bufferSize = 1024
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { buffer.deallocate() }
while inputStream.hasBytesAvailable {
let length = inputStream.read(buffer, maxLength: bufferSize)
if length > 0 {
write(buffer, maxLength: length)
}
}
inputStream.close()
}
}
順便說一句,使用檔案而不是檔案上傳和下載的優點之一Data是記憶體占用更小,避免在任何給定時間將整個資產加載到記憶體中。因此,本著這種精神,我使用一個小緩沖區將影像的內容寫入臨時檔案。這在上傳圖片時可能并不重要,但在上傳更大的資產(如視頻)時可能變得必不可少。
無論如何,以上內容還確定了使用此擴展的資產的 mimetype:
extension URL {
/// Mime type for the URL
///
/// Requires `import UniformTypeIdentifiers` for iOS 14 solution.
/// Requires `import MobileCoreServices` for pre-iOS 14 solution
var mimeType: String {
if #available(iOS 14.0, *) {
return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream"
} else {
guard
let identifier = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
let mimeType = UTTypeCopyPreferredTagWithClass(identifier, kUTTagClassMIMEType)?.takeRetainedValue() as String?
else {
return "application/octet-stream"
}
return mimeType
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/537465.html
標籤:ios迅速春天图片网址
上一篇:帶有TransactionAwareDataSourceProxy的jooqDataSourceConnectionProvider不參與春季交易
