Salesforce中调用REST API上传文件

昨天接到任务,说是调用某个REST API上传文件一直调不通,让我看一下。先用Flow调试了一下Apex代码,提示415错误,看了下代码,Content-Type设成json了,改成multipart/form-data,这下不提示415了,但提示400错误。

于是只好查资料,找了半天,说是base64编码的问题,从*上扒下来一段代码,再试,倒是不提示400了,却又出来个错误,说什么starting boundary找不到,无法解析Content-Disposition: filename。摸不着头脑,试了半天,却发现是由于犯了个愚蠢的错误,httpRequest的Body没有替换成用base64重新编码好的,改过来,再试,果然成功了。

具体的做法:

关键是*上的那段代码,抄录如下:

public with sharing class UploadFileHelper {
        //  The boundary is alligned so it doesn‘t produce padding characters when base64 encoded.
        private final static string Boundary = 1ff13444ed8140c7a32fc4e6451aa76d;
    
        /**
         *  Returns the request‘s content type for multipart/form-data requests.
         */
        public static string GetContentType() {
            return multipart/form-data; charset="UTF-8"; boundary=" + Boundary + ";
        }
    
        /**
         *  Pad the value with spaces until the base64 encoding is no longer padded.
         */
        private static string SafelyPad(
            string value,
            string valueCrLf64,
            string lineBreaks) {
            string valueCrLf = ‘‘;
            blob valueCrLfBlob = null;
    
            while (valueCrLf64.endsWith(=)) {
                value +=  ;
                valueCrLf = value + lineBreaks;
                valueCrLfBlob = blob.valueOf(valueCrLf);
                valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
            }
    
            return valueCrLf64;
        }
    
        /**
         *  Write a boundary between parameters to the form‘s body.
         */
        public static string WriteBoundary() {
            string value = -- + Boundary + \r\n;
            blob valueBlob = blob.valueOf(value);
    
            return EncodingUtil.base64Encode(valueBlob);
        }
    
        /**
         *  Write a boundary at the end of the form‘s body.
         */
        public static string WriteBoundary(
            EndingType ending) {
            string value = ‘‘;
    
            if (ending == EndingType.Cr) {
                //  The file‘s base64 was padded with a single ‘=‘,
                //  so it was replaced with ‘\r‘. Now we have to
                //  prepend the boundary with ‘\n‘ to complete
                //  the line break.
                value += \n;
            } else if (ending == EndingType.None) {
                //  The file‘s base64 was not padded at all,
                //  so we have to prepend the boundary with
                //  ‘\r\n‘ to create the line break.
                value += \r\n;
            }
            //  Else:
            //  The file‘s base64 was padded with a double ‘=‘,
            //  so they were replaced with ‘\r\n‘. We don‘t have to
            //  do anything to the boundary because there‘s a complete
            //  line break before it.
    
            value += -- + Boundary + --;
    
            blob valueBlob = blob.valueOf(value);
    
            return EncodingUtil.base64Encode(valueBlob);
        }
    
        /**
         *  Wirte a file to the form‘s body.
         */
        public static WriteFileResult WriteFile(
            string key,
            string value,
            string mimeType,
            blob fileBlob) {
            EndingType ending = EndingType.None;
            string contentDisposition = Content-Disposition: form-data; name=" + key + "; filename=" + value + ";
            string contentDispositionCrLf = contentDisposition + \r\n;
            blob contentDispositionCrLfBlob = blob.valueOf(contentDispositionCrLf);
            string contentDispositionCrLf64 = EncodingUtil.base64Encode(contentDispositionCrlfBlob);
            string content = SafelyPad(contentDisposition, contentDispositionCrLf64, \r\n);
            string contentType = Content-Type:  + mimeType;
            string contentTypeCrLf = contentType + \r\n\r\n;
            blob contentTypeCrLfBlob = blob.valueOf(contentTypeCrLf);
            string contentTypeCrLf64 = EncodingUtil.base64Encode(contentTypeCrLfBlob);
    
            content += SafelyPad(contentType, contentTypeCrLf64, \r\n\r\n);
    
            string file64 = EncodingUtil.base64Encode(fileBlob);
            integer file64Length = file64.length();
            string file64Ending = file64.substring(file64Length - 3, file64Length);
    
            if (file64Ending.endsWith(==)) {
                file64Ending = file64Ending.substring(0, 1) + 0K;//   0K = \r\n
                file64 = file64.substring(0, file64Length - 3) + file64Ending;
                ending = EndingType.CrLf;
            } else if (file64Ending.endsWith(=)) {
                file64Ending = file64Ending.substring(0, 2) + N;//    N = \r
                file64 = file64.substring(0, file64Length - 3) + file64Ending;
                ending = EndingType.Cr;
            }
    
            content += file64;
    
            return new WriteFileResult(content, ending);
        }
    
        /**
         *  Write a key-value pair to the form‘s body.
         */
        public static string WriteBodyParameter(
            string key,
            string value) {
            string contentDisposition = Content-Disposition: form-data; name=" + key + ";
            string contentDispositionCrLf = contentDisposition + \r\n\r\n;
            blob contentDispositionCrLfBlob = blob.valueOf(contentDispositionCrLf);
            string contentDispositionCrLf64 = EncodingUtil.base64Encode(contentDispositionCrLfBlob);
            string content = SafelyPad(contentDisposition, contentDispositionCrLf64, \r\n\r\n);
            string valueCrLf = value + \r\n;
            blob valueCrLfBlob = blob.valueOf(valueCrLf);
            string valueCrLf64 = EncodingUtil.base64Encode(valueCrLfBlob);
    
            content += SafelyPad(value, valueCrLf64, \r\n);
    
            return content;
        }
    
        /**
         *  Helper class containing the result of writing a file‘s blob to the form‘s body.
         */
        public class WriteFileResult {
            public final string Content { get; private set; }
            public final EndingType EndingType { get; private set; }
    
            public WriteFileResult(
                string content,
                EndingType ending) {
                this.Content = content;
                this.EndingType = ending;
            }
        }
    
        /**
         *  Helper enum indicating how a file‘s base64 padding was replaced.
         */
        public enum EndingType {
            Cr,
            CrLf,
            None
        }
 
}

其中Boundary 的值是个GUID去掉短横。可见这里关键是base64编码的处理。

调用的代码如下:

public static HttpResponse uploadFile(string url, string fileName, string fileMimeType, blob fileBlob) {
    string contentType = UploadFileHelper.GetContentType();

    string form64 = ‘‘;

    form64 += UploadFileHelper.WriteBoundary();
    UploadFileHelper.WriteFileResult result = UploadFileHelper.WriteFile(‘file‘, fileName, fileMimeType, fileBlob);

    form64 += result.Content;
    form64 += UploadFileHelper.WriteBoundary(result.EndingType);

    blob formBlob = EncodingUtil.base64Decode(form64);
    string contentLength = string.valueOf(formBlob.size());

    HttpRequest request = new HttpRequest();
    request.setEndpoint(url);
    request.setHeader(‘Connection‘, ‘keep-alive‘);
    request.setHeader(‘Content-Length‘, contentLength);
    request.setHeader(‘Content-Type‘, contentType);
    request.setBodyAsBlob(formBlob);
    request.setMethod(‘POST‘);
    request.setTimeout(120000);
    return new Http().send(request);
}

 

Salesforce中调用REST API上传文件

上一篇:AcWing 146. 序列


下一篇:如何降低API文档对接成本