如何用VBA MSXML2.XMLHTTP正确编码GIF适配Confluence附件API?
解决Confluence Create Attachment API上传GIF损坏问题
核心问题分析
- VBA字符串默认是UTF-16编码,而GIF属于二进制文件,包含大量非UTF-16兼容的字节(如0x00、单字节扩展ASCII)
- 你当前使用的
StrConv(fileStream.Read(), vbUnicode)会把二进制字节按系统默认代码页转成UTF-16字符串,这个过程会丢失或篡改原始二进制数据,导致上传后的文件损坏 - 直接用字符串拼接
multipart/form-data请求体,会因VBA字符串的编码特性进一步破坏文件内容
正确解决方案:用ADODB.Stream拼接二进制请求体
全程使用ADODB.Stream处理二进制流,避免将文件数据转成VBA字符串,确保请求体的二进制完整性:
步骤1:编写二进制文件读取函数
直接返回文件的字节数组,不做编码转换:
Function ReadFileBinary(filePath As String) As Byte() Dim fileStream As Object Set fileStream = CreateObject("ADODB.Stream") fileStream.Type = 1 ' 二进制模式 fileStream.Open fileStream.LoadFromFile filePath ReadFileBinary = fileStream.Read() fileStream.Close Set fileStream = Nothing End Function
步骤2:构建完整的multipart/form-data二进制流
用ADODB.Stream依次拼接边界、文本字段和二进制文件数据:
Sub UploadGifToConfluence() Dim http As Object Set http = CreateObject("MSXML2.XMLHTTP.6.0") Dim boundary As String boundary = "------IMabOUnDdfdfAaAAAA" ' 自定义边界,确保不与文件内容冲突 Dim reqStream As Object Set reqStream = CreateObject("ADODB.Stream") reqStream.Type = 1 ' 二进制模式 reqStream.Open ' 写入文件字段的头部文本(转成UTF-8二进制) Dim fileHeader As String fileHeader = "--" & boundary & vbCrLf & _ "Content-Disposition: form-data; name=""file""; filename=""ttmRecordTypeImage19.gif""" & vbCrLf & _ "Content-Type: image/gif" & vbCrLf & vbCrLf reqStream.Write StrConv(fileHeader, vbFromUnicode) ' 写入GIF二进制数据 reqStream.Write ReadFileBinary("C:\你的文件路径\ttmRecordTypeImage19.gif") ' 写入minorEdit字段(转成UTF-8二进制) Dim fieldContent As String fieldContent = vbCrLf & "--" & boundary & vbCrLf & _ "Content-Disposition: form-data; name=""minorEdit""" & vbCrLf & vbCrLf & _ "true" & vbCrLf & _ "--" & boundary & "--" & vbCrLf reqStream.Write StrConv(fieldContent, vbFromUnicode) ' 定位到流的起始位置 reqStream.Position = 0 ' 发送请求 http.Open "POST", "https://你的Confluence域名/rest/api/content/{contentId}/child/attachment", False http.setRequestHeader "Authorization", GetAuth http.setRequestHeader "X-Atlassian-Token", "nocheck" http.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary ' 发送二进制流数据 http.send reqStream.Read() ' 处理响应结果 If http.Status = 200 Or http.Status = 201 Then Debug.Print "上传成功" Else Debug.Print "上传失败:" & http.Status & " - " & http.responseText End If reqStream.Close Set reqStream = Nothing Set http = Nothing End Sub
关键细节说明
- 禁止用字符串承载二进制数据:VBA字符串无法正确存储所有二进制字节(如0x00会被当作字符串结束符),必须用Byte数组或ADODB.Stream处理
- 文本部分转UTF-8:
multipart/form-data的文本字段(边界、头部)需要UTF-8编码,通过StrConv(text, vbFromUnicode)将VBA的UTF-16字符串转成UTF-8二进制 - 流拼接保证完整性:用ADODB.Stream的Write方法依次拼接各部分,避免手动拼接导致的字节丢失
- 边界唯一性:边界字符串不要包含文件中可能出现的内容,防止Confluence解析请求体出错
排查验证方法
- 对比本地文件与Confluence中附件的MD5值:若不一致,说明数据传输过程中被篡改
- 用抓包工具查看请求体中的二进制文件数据,确认与原文件是否一致
- 检查Confluence返回的附件元数据,验证文件大小、MD5是否匹配本地文件
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

