0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Swift】AlamofireでAmazonS3の署名付きURL(pre-signed URL)に画像をアップロードする

Last updated at Posted at 2024-05-08

はじめに

S3へ画像をアップロードするため、pre-signed URLを取得したあとAlamofireの.uploadメソッドで画像データをアップロードしようとすると、403エラーとなりました。

※Alamofire:5.9.1

   /// Creates an `UploadRequest` for the given `Data`, `URLRequest` components, and `RequestInterceptor`.
    ///
    /// - Parameters:
    ///   - data:            The `Data` to upload.
    ///   - convertible:     `URLConvertible` value to be used as the `URLRequest`'s `URL`.
    ///   - method:          `HTTPMethod` for the `URLRequest`. `.post` by default.
    ///   - headers:         `HTTPHeaders` value to be added to the `URLRequest`. `nil` by default.
    ///   - interceptor:     `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
    ///   - fileManager:     `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
    ///                      default.
    ///   - requestModifier: `RequestModifier` which will be applied to the `URLRequest` created from the provided
    ///                      parameters. `nil` by default.
    ///
    /// - Returns:           The created `UploadRequest`.
    open func upload(_ data: Data,
                     to convertible: URLConvertible,
                     method: HTTPMethod = .post,
                     headers: HTTPHeaders? = nil,
                     interceptor: RequestInterceptor? = nil,
                     fileManager: FileManager = .default,
                     requestModifier: RequestModifier? = nil) -> UploadRequest {
        let convertible = ParameterlessRequestConvertible(url: convertible,
                                                          method: method,
                                                          headers: headers,
                                                          requestModifier: requestModifier)

        return upload(data, with: convertible, interceptor: interceptor, fileManager: fileManager)
    }

ハマりどころさんだったので、そのときの対処法と調査記録を残します。

原因

こちらの記事がサンプルを挙げて詳しく書いてくださっています🙏※記事自体は2019年(5年前)のものとなります
[Swift] Alamofireの仕組みを使ってiOSからAWS S3のPre-Signed URLに画像をアップロードしてみる

  • 403の原因は使用していた.uploadメソッドのHTTPメソッドが.postとなっていること
  • 画像データが破損するケースがあるので、その対処法を記載されている

対応

上記記事を参考にアップロードメソッドを実装してみました。

    private let uploadURL: String
    private let headers: HTTPHeaders = ["Content-Type": "image/jpeg"]
    
    init(uploadURL: String) {
        self.uploadURL = uploadURL
    }
    
    /// 画像データをS3へアップロードする
    /// - Note: AF.uploadで.postを使っている場合はAmazon S3 Pre-Signed URLでアップロードするときに403エラーの原因となる
    /// - Parameters:
    ///   - imageData: 画像データ
    ///   - res: アップロード結果を示す結果ハンドラー、成功または失敗の結果が渡される
    func uploadImageToAmazonS3(imageData: Data, res: @escaping (Result<Void, Error>) -> Void) {
        do {
            guard let url = URL(string: self.uploadURL) else {
                throw URLError(.badURL)
            }
            
            let urlRequest = try URLRequest(
                url: url,
                method: .put,
                headers: headers
            )
            
            AF.upload(imageData, with: urlRequest).response { response in
                switch response.result {
                case .success:
                    res(.success(()))
                case .failure(let error):
                    res(.failure(error))
                }
            }
        } catch {
            res(.failure(error))
        }
    }

メソッドはこちらを使っています

    /// Creates an `UploadRequest` for the given `Data` using the `URLRequestConvertible` value and `RequestInterceptor`.
    ///
    /// - Parameters:
    ///   - data:        The `Data` to upload.
    ///   - convertible: `URLRequestConvertible` value to be used to create the `URLRequest`.
    ///   - interceptor: `RequestInterceptor` value to be used by the returned `DataRequest`. `nil` by default.
    ///   - fileManager: `FileManager` instance to be used by the returned `UploadRequest`. `.default` instance by
    ///                  default.
    ///
    /// - Returns:       The created `UploadRequest`.
    open func upload(_ data: Data,
                     with convertible: URLRequestConvertible,
                     interceptor: RequestInterceptor? = nil,
                     fileManager: FileManager = .default) -> UploadRequest {
        upload(.data(data), with: convertible, interceptor: interceptor, fileManager: fileManager)
    }
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?