如何用SuiteScript实现等效cURL的multipart/form-data二进制ZIP上传?
NetSuite SuiteScript实现multipart/form-data二进制文件上传问题
需求与问题背景
在NetSuite中开发Map/Reduce脚本,通过N/compress生成ZIP文件,需要以HTTPS POST的multipart/form-data格式上传至第三方API。API要求接收原始二进制ZIP文件,不支持Base64编码。已通过Postman/cURL验证API正常,cURL示例如下:
curl --location 'https://<endpoint>/documents/zip' \ --header 'Authorization: <JWT_TOKEN>' \ --form 'file=@"file.zip"' \ --form 'companyId=<COMPANY_ID>'
现有代码尝试手动构建multipart请求体,但无法正确发送原始二进制文件,核心疑问:
- 如何实现等效于cURL
--form 'file=@file.zip'的原始二进制文件上传? - NetSuite是否有官方支持/推荐的方案,用于向不接受Base64的第三方API上传二进制文件?
现有代码片段:
var zipContent = zipFile.getContents(); // ZIP from File Cabinet var body = []; body.push('--' + boundary); body.push('Content-Disposition: form-data; name="companyId"'); body.push(''); body.push(companyId); body.push('--' + boundary); body.push('Content-Disposition: form-data; name="file"; filename="' + zipFile.name + '"'); body.push('Content-Type: application/zip'); body.push(''); body.push(zipContent); body.push('--' + boundary + '--'); var response = https.post({ url: uploadUrl, headers: { 'Authorization': 'Bearer ' + token, 'Content-Type': 'multipart/form-data; boundary=' + boundary }, body: body.join('\r\n') });
解决方案
你的核心问题是:zipFile.getContents()返回的是Base64编码字符串,直接用字符串拼接请求体会破坏原始二进制结构。以下是NetSuite官方推荐的处理方案:
方法:二进制缓冲区拼接请求体
利用N/encode模块将Base64编码的文件内容转为二进制缓冲区,再将表单文本部分、二进制文件、结尾边界合并为完整的二进制请求体,避免字符串编码导致的文件损坏。
完整示例代码:
define(['N/file', 'N/https', 'N/encode', 'N/log'], function(file, https, encode, log) { function execute() { // 配置参数 const zipFileId = '替换为你的ZIP文件柜ID'; const jwtToken = '替换为你的JWT Token'; const targetCompanyId = '替换为你的Company ID'; const uploadEndpoint = 'https://<endpoint>/documents/zip'; const boundary = `----NS-Multipart-Boundary-${Date.now()}`; // 加载ZIP文件 const zipFile = file.load({ id: zipFileId }); // 构建表单字段的文本头部 const formPart = [ `--${boundary}`, 'Content-Disposition: form-data; name="companyId"', '', targetCompanyId, `--${boundary}`, `Content-Disposition: form-data; name="file"; filename="${zipFile.name}"`, 'Content-Type: application/zip', '', // 头部与二进制内容之间必须有空白行 '' ].join('\r\n'); // 构建请求结尾边界 const endBoundary = `\r\n--${boundary}--`; // 将文本部分转为二进制缓冲区 const formPartBuffer = encode.convert({ string: formPart, inputEncoding: encode.Encoding.UTF_8, outputEncoding: encode.Encoding.BINARY }); // 将ZIP文件的Base64内容转为原始二进制缓冲区 const zipBinaryBuffer = encode.convert({ string: zipFile.getContents(), inputEncoding: encode.Encoding.BASE_64, outputEncoding: encode.Encoding.BINARY }); // 将结尾边界转为二进制缓冲区 const endBoundaryBuffer = encode.convert({ string: endBoundary, inputEncoding: encode.Encoding.UTF_8, outputEncoding: encode.Encoding.BINARY }); // 合并所有二进制部分 const fullRequestBody = formPartBuffer + zipBinaryBuffer + endBoundaryBuffer; // 发送POST请求 const response = https.post({ url: uploadEndpoint, headers: { 'Authorization': `Bearer ${jwtToken}`, 'Content-Type': `multipart/form-data; boundary=${boundary}` }, body: fullRequestBody }); log.debug('上传结果', response.body); } return { execute }; });
关键注意事项
- 禁止字符串拼接二进制数据:字符串会自动将二进制转为UTF-8编码,破坏ZIP文件的原始字节结构
- 边界唯一性:建议加入时间戳生成唯一边界,避免与文件内容冲突
- 格式规范:每个表单部分的头部与内容之间必须用
\r\n\r\n分隔(代码中通过空行实现) - 结尾边界格式:必须以
--boundary--结尾,前面需添加换行符
官方支持说明
NetSuite官方文档明确指出,向第三方API上传二进制文件时,必须通过N/encode.convert将Base64编码的文件内容转换为二进制格式,再构建符合multipart/form-data规范的请求体。可参考N/encode模块的convert方法、N/https模块的POST请求参数说明。
内容的提问来源于stack exchange,提问作者user32280537
相关产品推荐
相关产品推荐

