"Invalid multipart payload format" 通过 HTTPRequest 和 VBA 尽管与成功的浏览器发起的请求相同的负载

"Invalid multipart payload format" via HTTPRequest with VBA despite identical payload to successful browser initiated requests

我正在尝试使用 VBA 将文件上传到网络服务,遵循通过网络浏览器上传文档时发送的 form-data 多部分结构,但是我收到“400:无效多部分有效负载格式”响应,尽管在请求中发送(据我所知)相同的有效负载。

对于我的测试用例,我创建了一个名为 test.txt 的 txt 文档,其中包含“TestContents”。我已经使用网络浏览器上传了这个文件,也尝试过使用 VBA(如下所示)。花一些时间比较 Chrome 的有效载荷与我自己 VBA 生成的有效载荷,我看不出有任何差异。

我正在使用以下代码创建多部分有效负载并将其发送到 Web 服务(URL 部分混淆)并使用以下问题帮助 re-write 这几次解决这个问题的追求:[

(对内部的任何混乱表示歉意 - 我一直在更改 re-writing 这已经有一段时间了,所以可能有些不整洁)

Private Function toArray(inData As String)

    Dim objADODB As Object: Set objADODB = CreateObject("ADODB.Stream")
    
     objADODB.Type = 2
     objADODB.Charset = "_autodetect"
     objADODB.Open
     objADODB.WriteText (inData)
     objADODB.Position = 0
     objADODB.Type = 1
     toArray = objADODB.Read()

     Set objADODB = Nothing
End Function

Private Function readBinary(filePath As String)

    Dim objADODB As Object: Set objADODB = CreateObject("ADODB.Stream")
    
    objADODB.Type = 1
    objADODB.Open
    objADODB.LoadFromFile filePath
    readBinary = objADODB.Read
    objADODB.Close
    
    Set objADODB = Nothing
End Function

Public Sub sendDocument(ByVal inID As String, ByVal tags As String, ByVal docContentType As String, ByVal docFilePath As String)

     Dim objADODB As Object
     Dim objHTTP As Object
    
     Dim boundary As String: boundary = "----WebKitFormBoundaryeeYChAY7UlBEI63d" 'Set like this so i can debug like-for-like with browser payload
     Dim docFileName As String: docFileName = Mid(docFilePath, InStrRev(docFilePath, "\") + 1)

     '(structure is file, material, tags if there are any)
     Set objADODB = CreateObject("ADODB.Stream")
    
     With objADODB
         .Type = 1
         .Open
        
         .Write toArray("--" & boundary & Chr(10))
         .Write toArray("Content-Disposition: form-data; name=""file""; filename=""" & docFileName & """" & Chr(10) & _
                 "Content-Type: " & docContentType & Chr(10) & Chr(10))
         .Write readBinary(docFilePath)
         .Write toArray(Chr(10) & "--" & boundary & Chr(10))
         .Write toArray("Content-Disposition: form-data; name=""material""" & Chr(10) & Chr(10) & inID & Chr(10))
         If tags <> "" Then .Write toArray("Content-Disposition: form-data; name=""tags""" & Chr(10) & Chr(10) & tags & Chr(10))
         .Write toArray("--" & boundary & "--")
         .Position = 0
     End With

     If Not validateID(inID) Then
         MsgBox ("ID must be 4-5 digits long")
         Exit Sub
     End If
    
     If auth = "" Then
         MsgBox "Login is required. Click OK to log in"
         Call getAuth
     End If
    
     Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
    
     With objHTTP
         .Open "POST", "https://xxx.xxx/hapi/document", False
         .setRequestHeader "Authorization", auth
         .setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary
         .send (objADODB.Read())
         MsgBox .responseText
     End With
    
     bStatusOK = objHTTP.status = 200
    
     If objHTTP.status = 401 Then
         MsgBox ("Login is invalid/expired. Please reauthenticate")
         Call getAuth
     End If
End Sub

当查看请求的表单数据时,上面生成的负载与 Chrome 的检查器 window 中存在的负载相同,即:

------WebKitFormBoundaryeeYChAY7UlBEI63d
Content-Disposition: form-data; name="file"; filename="Test.txt"
Content-Type: text/plain

TestContents
------WebKitFormBoundaryeeYChAY7UlBEI63d
Content-Disposition: form-data; name="material"

16145
------WebKitFormBoundaryeeYChAY7UlBEI63d--

我开始怀疑它的编码不正确。我注意到浏览器调用使用 header

Accept-Encoding: gzip, deflate, br

..当我尝试复制这个或任何单一类型(除了 br)时,我仍然收到相同的消息,但以 VBA 当地人 window 无法理解的格式回复。我在其他 POST 和 PUT 请求中取得了成功,无需指定 Accept-Encoding 即可发送 JSON 或文本有效负载,因此我不确定这是否是继续前进的正确路径。

如果有人能够提供一些帮助,我将非常感激。

谢谢!

如果您有标签参数,它将缺少起始边界。

If tags <> "" Then
    .Write toArray("--" & boundary & vbCrLf)
    .Write toArray("Content-Disposition: form-data; name=""tags""" & vbCrLf & vbCrLf & tags & vbCrLf)
End If

感谢CDP1802的评论解决了!需要 VbCrLf 而不是 Chr(10)

构建表单数据的工作部分现在如下所示:

Set objADODB = CreateObject("ADODB.Stream")
    
With objADODB
    .Type = 1
    .Open
    
    .Write toArray("--" & boundary & vbCrLf)
    .Write toArray("Content-Disposition: form-data; name=""file""; filename=""" & docFileName & """" & vbCrLf & _
             "Content-Type: " & docContentType & vbCrLf & vbCrLf)
    .Write readBinary(docFilePath)
    .Write toArray(vbCrLf & "--" & boundary & vbCrLf)
    .Write toArray("Content-Disposition: form-data; name=""material""" & vbCrLf & vbCrLf & inID & vbCrLf)
    If tags <> "" Then
        .Write toArray("--" & boundary & vbCrLf)
        .Write toArray("Content-Disposition: form-data; name=""tags""" & vbCrLf & vbCrLf & tags & vbCrLf)
    End If
    .Write toArray("--" & boundary & "--")
    .Position = 0
End With