使用 AlamoFire 和预签名 URL 将图像上传到 S3 存储桶时出现问题

Posted

技术标签:

【中文标题】使用 AlamoFire 和预签名 URL 将图像上传到 S3 存储桶时出现问题【英文标题】:Problem Uploading Images to S3 Bucket Using AlamoFire and Presigned URL 【发布时间】:2021-03-31 02:50:04 【问题描述】:

我为我的应用上传到 S3 的方法是向我的 php 后端发送一个获取请求以生成一个预签名 URL。我知道后端设置正确,因为运行以下命令成功将图像上传到 S3 存储桶:

curl -v -H "Content-Type: image/jpeg" -T ./test.jpeg '<presignedURL>'

但是,我在尝试在 Swift 中上传图片时遇到了问题。这是我目前的实现(请忽略垃圾,硬编码,非错误检查):

后端

<?php
require '../vendor/autoload.php';

use Aws\S3\S3Client;
use Aws\Exception\AwsException;

$response = array();

$client = S3Client::factory(array(
    'profile' => 'default',
    'version' => 'latest',
    'region' => 'us-east-2',
    'signature' => 'v4'
));

$command = $client->getCommand('PutObject', array(
    'Bucket'      => 'test',
    'Key'         => 'test.jpeg',
    'ContentType' => 'image/jpeg',
    'Body'        => ''
));

$signedUrl = $command->createPresignedUrl('+5 minutes');

$response['error'] = false;
$response['url'] = $signedUrl;

echo json_encode($response);

Swift 代码

import Foundation
import Alamofire

let getTokenURL = "http://192.168.1.59:8000/v1/upload.php"

func submitImage(image: UIImage, completion: @escaping (NSDictionary) -> Void) 
    
    AF.request(getTokenURL, method: .get).responseJSON  response in
        
        switch response.result 
        case.success(let value):
            let jsonData = value as! NSDictionary
            let url = jsonData.value(forKey: "url") as! String
            
            performUpload(image: image, postURL: url)
        
        case.failure(_):
            let error_msg: NSDictionary = [
                "error" : true,
                "message" : "Unknown error occurred. Please try again",
            ]
            
            //completion(error_msg)
        
    
                                


func performUpload(image: UIImage, postURL: String) 
    let imageData = image.jpegData(compressionQuality: 0.50)!
    
    AF.upload(imageData, to: postURL, headers: ["Content-Type":"image/jpeg"])    //likely the culprit line

当前 URL 从 submitImage() 中的 get 请求返回,并调用 performUpload(),这使得罪魁祸首(可能)成为我 Swift 代码段的最后一个问题。我在阅读文档时无法弄清楚我应该做什么,并且大多数关于这个主题的指南都过时了,因为 AlamoFire 已经改变了它们的语法。任何帮助将不胜感激。谢谢!

编辑: 我已经调整了 performUpload() 函数。它现在将数据上传到 s3 存储桶,但是无法打开图像。我怀疑这是因为请求中的标头不正确。从调试中我可以看出 Content-Type 标头无论如何都是“multipart/form-data”,所以我不确定这种方法是否可行:

struct HTTPBinResponse: Decodable  let url: String 

func performUpload(image: UIImage, postURL: String) 
    let imageData = image.jpegData(compressionQuality: 0.50)!
    
    AF.upload(multipartFormData:  multipartFormData in
        multipartFormData.append(imageData, withName: "file", mimeType: "image/jpeg")
    , to: postURL, method: .put, headers: ["Content-Type":"image/jpeg"]).responseDecodable(of: HTTPBinResponse.self)  response in
            debugPrint(response)
      

【问题讨论】:

尝试使用multipart form data 请求发送图像数据并查看。 @Isuru 请检查我的编辑 请求标头为multipart/form-data 没有任何问题。应该是这样的。从标题中删除"Content-Type":"image/jpeg",看看会发生什么。 @Isuru 还是同样的问题 @Isuru 有点尴尬,但在我原来的解决方案中添加“method: .put”作为参数解决了它 【参考方案1】:

对于未来的读者,这里的关键是添加method: .put!这个问题的其他一切都很好。

我还发现您必须使用空的内容类型标头。 S3 很奇怪。

AF.upload(imageData, to: postURL, method: .put, headers: ["Content-Type": ""])

【讨论】:

以上是关于使用 AlamoFire 和预签名 URL 将图像上传到 S3 存储桶时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Alamofire 将图像上传到服务器不起作用

在 iOS 9 问题上使用 Alamofire 上传带有 URL 参数的图像

尝试通过 Alamofire 4.0 上传图像时,类型“ParameterEncoding”没有成员“URL”

Firebase 和 Alamofire Url TableViewCell 图像加载问题 Swift 4

使用 Alamofire 从 UIImagePickerController 上传图像

如何使用 Alamofire Swift 4 将图像填充到 UICollectionView