使用Visualforce与Apex上传图片至S3后无法正常显示如何解决?
你代码存在3个核心问题,直接导致上传到S3的文件不是合法的图片格式:
- 没有移除DataURL的base64前缀:JS通过
readAsDataURL获取的结果自带data:image/png;base64,格式的前缀,你直接将完整字符串传到后端处理,前缀会被当成图片内容的一部分,导致最终生成的二进制文件不是合法的图片格式。 - Apex侧存在多余的二次编码:你拿到传入的base64字符串后,先调用
Blob.valueOf()转换为二进制,再重新做base64编码,相当于对原内容做了二次编码,彻底破坏了原图片的二进制结构。 - Content-Length计算错误:你传入的是base64字符串的长度,但实际发送给S3的是解码后的二进制Blob,两者长度完全不匹配,S3会判定内容存在异常。
修正方案
1. 前端Visualforce代码修正
补全FileReader的初始化逻辑,同时移除DataURL的前缀,只将纯base64内容传到后端:
<input class="slds-input-custom" id="logo" name="bsLogo" type="file" /> <button id="submtBtn" onclick="toSubmit()" label="Submit" title="Submit" class="cSubmit" >Submit</button> <apex:form id="formId"> <apex:actionFunction name="setParamAF" action="{!apexMethod}" rerender="panelId" status="checkingId" oncomplete="onloadCallback();"> <apex:param name="vBusiLogo" value=""/> </apex:actionFunction> </apex:form> <script> function toSubmit(){ const selectFile = document.getElementById('logo').files[0]; if(!selectFile) return; // 补全FileReader实例初始化 const reader = new FileReader(); reader.readAsDataURL(selectFile); reader.onload = function(){ const dataURL = reader.result; // 移除base64前缀,仅传递纯编码内容 const pureBase64 = dataURL.split(',')[1]; setParamAF(pureBase64); }; } function onloadCallback(){ alert('uploaded'); } </script>
2. 后端Apex代码修正
去掉多余的编码步骤,直接解码传入的纯base64内容,同时修正Content-Length的取值,删除无效的Content-Encoding头:
String busiLogo = ''; public static void apexMethod(){ busiLogo = ApexPages.currentPage().getParameters().get('vBusiLogo'); String logoName = 'image.png'; String bucketname ='amazon-file-s3'; String host = 's3-ap-sample-1.amazonaws.com'; // 直接解码纯base64内容得到原图片二进制 Blob blobFile = EncodingUtil.base64Decode(busiLogo); HttpRequest req = new HttpRequest(); req.setMethod('PUT'); req.setEndpoint('callout:AmazonS3' + '/' + logoName); req.setHeader('Host', bucketname + '.' + host); // 用解码后的二进制实际长度作为Content-Length值 req.setHeader('Content-Length', String.valueOf(blobFile.size())); req.setHeader('Content-Type','image/png'); req.setHeader('Connection', 'keep-alive'); req.setHeader('Date', formattedDateString); req.setHeader('ACL', 'public-read-write'); req.setBodyAsBlob(blobFile); Http http = new Http(); HTTPResponse res = http.send(req); }
其他注意事项
如果上传的图片格式不固定为PNG,可以在JS中同时传递文件的MIME类型到Apex,动态设置Content-Type头,适配不同格式的文件。
可以在Apex中打印传入的busiLogo内容,确认前缀已经被完全移除,避免多余字符混入图片二进制。
内容的提问来源于stack exchange,提问作者Leonard
相关产品推荐
相关产品推荐

