当前位置: 首页 > 知识库问答 >
问题:

如何使用salesforce apex将较大的文件(大于12MB)上载到aws s3存储桶

太叔正文
2023-03-14

我需要一些帮助,以便从 salesforce 顶点服务器端将大文件上传到 s3 存储桶中。

我需要能够使用Http PUT操作拆分一个blob并将其上传到aws s3 bucket。我能够在一次上传中完成高达12MB的文件,因为这是Apex中PUT请求正文大小的限制。所以我需要能够使用多部分操作上传。我注意到s3允许部分上传并返回uploadId。想知道之前是否有人在salesforceapex代码中做过这项工作。我们将不胜感激。

提前感谢帕尔巴蒂·博斯。

这是代码。

public with sharing class AWSS3Service {

    private static Http http;

    @auraEnabled
    public static  void uploadToAWSS3( String fileToUpload , String filenm , String doctype){


        fileToUpload = EncodingUtil.urlDecode(fileToUpload, 'UTF-8');

        filenm = EncodingUtil.urlEncode(filenm , 'UTF-8'); // encode the filename in case there are special characters in the name 
        String filename = 'Storage' + '/' + filenm ;
        String attachmentBody = fileToUpload;

        String formattedDateString = DateTime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');




        // s3 bucket!
        String key = '**********' ;
        String secret = '********' ;
        String bucketname = 'testbucket' ;
        String region = 's3-us-west-2' ;



        String host = region + '.' + 'amazonaws.com' ; //aws server base url




    try{
        HttpRequest req = new HttpRequest();
        http = new Http() ;
        req.setMethod('PUT');
        req.setEndpoint('https://' + bucketname + '.' + host +  '/' +  filename );
        req.setHeader('Host', bucketname + '.' + host);

        req.setHeader('Content-Encoding', 'UTF-8');
        req.setHeader('Content-Type' , doctype);
        req.setHeader('Connection', 'keep-alive');
        req.setHeader('Date', formattedDateString);
        req.setHeader('ACL', 'public-read-write');


        String stringToSign = 'PUT\n\n' +
                doctype + '\n' +
                formattedDateString + '\n' +
                '/' + bucketname +  '/' + filename;


        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String signed = EncodingUtil.base64Encode(mac);
        String authHeader = 'AWS' + ' ' + key + ':' + signed;
        req.setHeader('Authorization',authHeader);

        req.setBodyAsBlob(EncodingUtil.base64Decode(fileToUpload)) ;



        HttpResponse response = http.send(req);

        Log.debug('response from aws s3 is ' + response.getStatusCode() + ' and ' + response.getBody());


    }catch(Exception e){
            Log.debug('error in connecting to s3 ' + e.getMessage());
            throw e ;
        }
    }

共有2个答案

舒宏富
2023-03-14

AWS SDK forJava公开了一个名为TransferManager的高级API,它简化了多部分上传(请参阅使用多部分上传API上传对象)。您可以从文件或流上传数据。您还可以设置高级选项,例如要用于多部分上传的部件大小,或者上传部件时要使用的并发线程数。您还可以设置可选的对象属性、储存类别或ACL。您可以使用PutObjectRequest和TransferManagerConfiguration类来设置这些高级选项。

这是https://docs.aws.amazon.com/AmazonS3/latest/dev/HLuploadFileJava.html.的示例代码

您可以调整您的Salesforce Apex代码:

import com.amazonaws.SdkClientException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.TransferManagerBuilder;
import com.amazonaws.services.s3.transfer.Upload;

import java.io.File;

public class HighLevelMultipartUpload {

    public static void main(String[] args) throws Exception {
        Regions clientRegion = Regions.DEFAULT_REGION;
        String bucketName = "*** Bucket name ***";
        String keyName = "*** Object key ***";
        String filePath = "*** Path for file to upload ***";

        try {
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                    .withRegion(clientRegion)
                    .withCredentials(new ProfileCredentialsProvider())
                    .build();
            TransferManager tm = TransferManagerBuilder.standard()
                    .withS3Client(s3Client)
                    .build();

            // TransferManager processes all transfers asynchronously,
            // so this call returns immediately.
            Upload upload = tm.upload(bucketName, keyName, new File(filePath));
            System.out.println("Object upload started");

            // Optionally, wait for the upload to finish before continuing.
            upload.waitForCompletion();
            System.out.println("Object upload complete");
        } catch (AmazonServiceException e) {
            // The call was transmitted successfully, but Amazon S3 couldn't process 
            // it, so it returned an error response.
            e.printStackTrace();
        } catch (SdkClientException e) {
            // Amazon S3 couldn't be contacted for a response, or the client
            // couldn't parse the response from Amazon S3.
            e.printStackTrace();
        }
    }
}
萧英光
2023-03-14

前几天我也在看这个问题,不幸的是,由于APEX堆大小限制为12MB,您从Salesforce外部进行这种转移会更好。https://developer . sales force . com/docs/atlas . en-us . apex code . meta/apex code/apex _ gov _ limits . htm

虽然可以使用多部分写入文件,但似乎无法将它们从html" target="_blank">数据库中取出,以便将它们拆分为可以发送的块。在堆栈交换中提出了类似的问题 - https://salesforce.stackexchange.com/questions/264015/how-to-retrieve-file-content-from-content-document-in-chunks-using-soql

 类似资料:
  • 目前,我正在尝试将一个文件上载到AmazonS3存储桶,我对此进行了一些研究,发现如果文件足够大,类TransferManager会将文件拆分为小块,然后使用多个线程并行上载。现在在应用程序中,我们正在创建一个AmazonS3客户端实例(在应用程序开始时创建的一个bean),并使用该AmazonS3客户端为用户上传文件所需的每个文件创建TransferManager类实例,文件上传完成后(由Tra

  • 我正在尝试上传非常大的文件,大约15-20 GB使用ASP.NET核心通过邮差。我已经调整了maxRequestLength和maxAllowedContentLength(如其他文章中所建议的那样),但是由于这些参数的最大限制大约是2GB,我仍然得到“请求过滤模块被配置为拒绝超过请求内容长度的请求。”错误。我怎么上传这么大的文件?

  • 但事实证明,Firebase无法从服务器端上传文件,正如它在文档中明确说明的那样: Firebase存储不包括在服务器端Firebase npm模块中。相反,您可以使用gcloud Node.js客户机。 我的第二次尝试是使用库,就像文档中提到的:

  • 根据文档,我必须把文件名传递给函数才能上传一个文件。 我想能做这样的事

  • 我有一个要求,我需要上传文件到谷歌云存储(他拥有并完全维护它)桶。 这个谷歌云存储桶是由我的客户创建的。 我是谷歌云的新手,有亚马逊S3的经验。我在服务器上运行SSI,以将事务数据加载到平面文件。 我为谷歌云创建了一个示例帐户,并安装了谷歌SDK。我可以通过gsutil手动上传文件。 我的问题是 > 我应该如何建议我的客户共享凭据? 我如何连接到谷歌云存储与提供凭据独立? 如何通过以上两个步骤将文