You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Salesforce Apex调用Zalo文件上传API时提示‘File not exist’问题

问题:调用Zalo文件上传API返回"File not exist!"错误

开发Zalo API获取文件令牌时,Apex代码调用后API返回状态码200,但响应体提示文件不存在:

{"error":-201,"message":"File not exist!"}

现有Apex代码

String fileId = '069HE0000010ZurYAE'; // contentDocumentId
String fileName = 'file-sample_150kB.pdf';
ContentVersion contentVersion = [SELECT Id, ContentSize, Title, ContentDocumentId, VersionData FROM ContentVersion WHERE ContentDocumentId = :fileId LIMIT 1];
Blob fileData = contentVersion.VersionData;

String boundary = '----MyBoundary';
String requestBody = '--' + boundary + '\r\n' +
    'Content-Disposition: form-data; name="field1"' + '\r\n' + 
    '--' + boundary + '\r\n' + 
    
    'Content-Disposition: form-data; name="file"; filename="' + fileName + '"' + '\r\n' + 
    
    'Content-Type: application/octet-stream' + '\r\n' + '\r\n' +
    
    fileData + '\r\n' + 
    
    '--' + boundary + '--' + '\r\n';
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://openapi.zalo.me/v2.0/oa/upload/file');
req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
req.setHeader('access_token', <access_token_here>);
req.setBody(requestBody);

Http h = new Http();
HttpResponse response = h.send(req);

可正常运行的curl请求

curl --location 'openapi.zalo.me/v2.0/oa/upload/file' \ 
--header 'access_token: <access_token_here>' \ 
--header 'Accept: application/json' \ 
--form 'file="@/C:/Users/Desktop/Sample Files/file-sample_150kB.pdf"'

该curl请求在Postman中可正常执行,但Apex代码调用报错。


问题原因

Apex中直接将Blob类型的文件数据与字符串拼接时,二进制数据会被强制转换为UTF-8字符串,导致文件内容损坏。Zalo API无法识别损坏的文件数据,因此返回"File not exist!"错误。

解决方案

使用HttpRequest.setBodyAsBlob()构建完整的二进制请求体,避免字符串与Blob拼接导致的编码问题。修正后的代码如下:

String fileId = '069HE0000010ZurYAE'; // contentDocumentId
String fileName = 'file-sample_150kB.pdf';
ContentVersion contentVersion = [SELECT Id, ContentSize, Title, ContentDocumentId, VersionData FROM ContentVersion WHERE ContentDocumentId = :fileId LIMIT 1];
Blob fileData = contentVersion.VersionData;

String boundary = '----MyBoundary';

// 构建表单字段部分(不需要可删除)
String fieldPart = '--' + boundary + '\r\n' +
    'Content-Disposition: form-data; name="field1"\r\n\r\n' +
    'your_field_value\r\n'; // 替换为field1的实际值

// 构建文件部分的头部
String fileHeaderPart = '--' + boundary + '\r\n' +
    'Content-Disposition: form-data; name="file"; filename="' + fileName + '"\r\n' +
    'Content-Type: application/octet-stream\r\n\r\n';

// 构建请求体结尾
String footerPart = '\r\n--' + boundary + '--\r\n';

// 将所有部分转换为Blob并拼接
Blob requestBodyBlob = Blob.valueOf(fieldPart) + Blob.valueOf(fileHeaderPart) + fileData + Blob.valueOf(footerPart);

HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://openapi.zalo.me/v2.0/oa/upload/file');
req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
req.setHeader('access_token', '<access_token_here>');
req.setBodyAsBlob(requestBodyBlob); // 用二进制方式传递请求体

Http h = new Http();
HttpResponse response = h.send(req);

关键说明

  • 禁止直接将Blob与字符串拼接,二进制文件转字符串会导致数据丢失或损坏
  • 使用setBodyAsBlob()传递完整的二进制请求体,确保文件数据原样传输
  • 若不需要field1参数,可删除对应的fieldPart,调整requestBodyBlob的拼接逻辑即可

内容的提问来源于stack exchange,提问作者Nisha Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 11:47:38