【问题标题】:Presigned Url multipart part upload always returns 403Presigned Url 分段上传总是返回 403
【发布时间】:2021-06-16 04:50:47
【问题描述】:

我在使用 Swift 中的预签名 url 在 S3 存储桶中以块的形式上传多部分数据时收到错误消息。

我的代码是:-

func AWSS3UploadMultipartData(data: Data, strVideoName : String, strContentType: String , _ completion: @escaping s3CompletionHandler)
 {
          let multipartRequest = AWSS3CreateMultipartUploadRequest()
          multipartRequest?.key = strVideoName
            multipartRequest?.bucket = S3BucketName
             multipartRequest?.contentType = strContentType
           let awsService = AWSS3.default()
         awsService.createMultipartUpload(multipartRequest!) { (multipartUploadOutput, error) in
                      self.multipartUploadId = multipartUploadOutput?.uploadId
                    self.completedPartsInfo = AWSS3CompletedMultipartUpload()
                  self.uploadAllParts()
         }        
 }
 func uploadAllParts ()
    {
           repeat {
                       // get the length of the chunk
                        let thisChunkSize = xxxxx;

                       // get the chunk data
                        let chunk = xxxxxx

                       //saving the file to Documents Directory in  chunkURL

                       self.uploadAWSPart(uploadDict: dict, fileURL: chunkURL!, mediaName : fileName, 
                         awsPartNumber: offset)

                       offset += thisChunkSize;

        } while (offset < length);
}

 func uploadAWSPart(uploadDict : [String : Any], fileURL : URL, mediaName : String, awsPartNumber : Int)
    {

        let getPreSignedURLRequest = AWSS3GetPreSignedURLRequest()
        getPreSignedURLRequest.bucket = S3BucketName
        getPreSignedURLRequest.key = mediaName
         getPreSignedURLRequest.httpMethod = AWSHTTPMethod.PUT;

   getPreSignedURLRequest.expires =  Date(timeIntervalSinceNow: 36 * 60 * 60);
 getPreSignedURLRequest.contentType = contentType
             getPreSignedURLRequest.setValue(self.multipartUploadId, forRequestParameter: "uploadId")
        getPreSignedURLRequest.setValue(String(awsPartNumber), forRequestParameter: "partNumber")

           let MD5 = self.md5File(url: fileURL)
            getPreSignedURLRequest.contentMD5 = MD5
          let presignedTask = 
            AWSS3PreSignedURLBuilder.default().getPreSignedURL(getPreSignedURLRequest)

presignedTask.continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask!) -> AnyObject! in
                if let presignedURL = task.result
                {

                      ///This is the response of presignedURL:-

                        *******************************************************
                          https://bucketName.s3-ap-south- 
                       1.amazonaws.com/c9e407127756360d54b85a469b728e0d_1534190164.75355.mp4? 
                        X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz- 
                         Credential=AKIAIBZJLCO6SJCZZ7YQ%2F20180813%2Fap-south- 
                          1%2Fs3%2Faws4_request&X-Amz-Date=20180813T195604Z&X-Amz- 
                         Expires=129599&X-Amz-SignedHeaders=content-md5%3Bcontent- 
 type%3Bhost&uploadId=RSjis.pARzI3IPESBYvxWhcY5ta_ybURr7fnUK4fKBVTTS9cMjyVfG4nmJVAu 
                     O.cQ.K7mSAPpLzLwW7CElIUyFaXnMmCTrr7A2p7r1KG79Q-&partNumber=0&X-Amz- 
                   Signature=f2d555fd64f80e1ba86c8ed0b0eb63a1b184304fcbfde6a91198163df2a67900

                   *********************************************************                

                    self.startUploadForPresignedURL (presignedURL as URL, chunkURL: fileURL, md5 : 

                     MD5!, MediaName : mediaName, strContentType : contentType, awsPartNumber: 
                          awsPartNumber)
                }
                return nil
            })
    }


func startUploadForPresignedURL (_ presignedURL:URL, chunkURL: URL,  md5 : String, MediaName : String, strContentType : String,  awsPartNumber: Int)
    {

       let request = NSMutableURLRequest(url: presignedURL)
        request.cachePolicy = .reloadIgnoringLocalCacheData        
        request.timeoutInterval =  Date(timeIntervalSinceNow: 36 * 60 * 60).timeIntervalSinceNow 
        request.httpMethod = "PUT"
        request.setValue("public-read", forHTTPHeaderField: "x-amz-acl")
        request.setValue(MediaName, forHTTPHeaderField: "filename")
        request.setValue(strContentType, forHTTPHeaderField: "Content-Type")
        request.setValue(self.md5File(url: chunkURL), forHTTPHeaderField: "Content-MD5")         
        let uploadTask = self.session?.uploadTask(with: request as URLRequest, fromFile: chunkURL)
        uploadTask?.taskDescription = String(awsPartNumber)
        uploadTask?.resume()
    }

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        print("\(#function)")
        if (error != nil) {
            print("didCompleteWithError error: \(String(describing: error?.localizedDescription))")
        }
        else {
            print("didCompleteWithError success: \(String(describing: task.response))")
        }
    }

错误是:-

<NSHTTPURLResponse: 0x1c4432b60> { URL: https://bucketName.s3-ap-Region.amazonaws.com/xxxxx.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIBZJLCO6SJCZZ7YQ%2F20180812%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Date=20180812T190423Z&X-Amz-Expires=129599&X-Amz-SignedHeaders=content-md5%3Bcontent-type%3Bhost&uploadId=rtRmP_xSnCVBURpnAnUFSbN5JLy9h11yDyDxtrTmMc9oAFMfIi95hX82bbupk497uIoHtC5tYXezK2fLcHb7fh_aR1win8eiAYCcKakmxvo-&partNumber=17825792&X-Amz-Signature=39d31e9f41371242099164702d329d8e81e6f4b16fabba0ed29507ceabc05130 } { Status Code: 403, Headers {
    Connection =     (
        close
    );
    "Content-Type" =     (
        "application/xml"
    );
    Date =     (
        "Sun, 12 Aug 2018 19:04:30 GMT"
    );
    Server =     (
        AmazonS3
    );
    "Transfer-Encoding" =     (
        Identity
    );
    "x-amz-id-2" =     (
        "0bmVCpzxQZRVYUSeEKIMrxq0rMd9Ts5eYne7timdoH++ThvvNJo+Wjq9Jhckx/AP1fNiaPhVhqQ="
    );
    "x-amz-request-id" =     (
        C171A1AE06D092EF
    );
} })

我尝试了不同的选项,但都没有奏效。我也尝试过使用 Alamofire 进行分段流上传,但同样的错误正在出现。我也将此问题发布到 github 中的 aws-sdk-ios,但他们直到现在也没有正确的答案。任何帮助将不胜感激。

【问题讨论】:

    标签: ios swift amazon-web-services


    【解决方案1】:

    您应该考虑使用 AWS Mobile iOS 开发工具包中提供的 TransferUtility,而不是滚动您自己的实施来进行分段上传。

    也就是说,查看您的代码,我突然想到的一件事是您在上传该部分的请求中设置了 x-amz-acl。部分不允许使用该标头(有关上传部分时所有允许标头的列表,请参阅https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPart.html),并且可能导致服务器将其作为无效请求拒绝。 x-amz-acl 标头应仅包含在 createMultiPart 请求中。 从部分上传中删除该标头,这应该可以解决 403 错误。

    请参阅第 1315 行 (https://github.com/aws/aws-sdk-ios/blob/7c6c287f5cf0313ef042d34f18b5f82b27298a30/AWSS3/AWSS3TransferUtility.m#L1315) 中的代码,了解 TransferUtility 如何为部件创建预签名 URL 并使用 NSURLSessionUploadTask 上传它。

    此外,请查看从第 131 行 (https://github.com/aws/aws-sdk-ios/blob/7c6c287f5cf0313ef042d34f18b5f82b27298a30/AWSS3/AWSS3TransferUtility%2BHeaderHelper.m#L131) 开始的代码,了解 TransferUtility 如何查找某些标头并将其从部分上传中剔除的详细信息。

    【讨论】:

    • @cbommas 感谢您的回复。但我不明白我的方法有什么问题。因为 AWSTransferUtility 不支持耗时超过 50 分钟的传输。所以,我正在使用这个。
    • @Aviru 不,您的方法没有任何问题,我只是建议您可以使用 TransferUtility 来避免使用多部分 API 的复杂性。
    【解决方案2】:

    所以我使用 AWSS3GetPreSignedURLRequest() 来获取 PUT presignedURL 并使用 URLSession.upload 使用它,一切正常。使用 Alamofire.upload 使用相同的精确参数,总是得到签名错误。想要使用 AWS 上传以外的东西,因为您无法控制重试或超时。

    【讨论】:

      猜你喜欢
      • 2020-10-05
      • 2017-09-28
      • 2015-12-23
      • 2018-08-15
      • 2021-11-17
      • 2015-03-04
      • 2021-03-23
      • 2015-10-23
      • 2018-08-28
      相关资源
      最近更新 更多