"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
我正在尝试使用 VBA 将文件上传到网络服务,遵循通过网络浏览器上传文档时发送的 form-data 多部分结构,但是我收到“400:无效多部分有效负载格式”响应,尽管在请求中发送(据我所知)相同的有效负载。
对于我的测试用例,我创建了一个名为 test.txt 的 txt 文档,其中包含“TestContents”。我已经使用网络浏览器上传了这个文件,也尝试过使用 VBA(如下所示)。花一些时间比较 Chrome 的有效载荷与我自己 VBA 生成的有效载荷,我看不出有任何差异。
我正在使用以下代码创建多部分有效负载并将其发送到 Web 服务(URL 部分混淆)并使用以下问题帮助 re-write 这几次解决这个问题的追求:[ (对内部的任何混乱表示歉意 - 我一直在更改 re-writing 这已经有一段时间了,所以可能有些不整洁) 当查看请求的表单数据时,上面生成的负载与 Chrome 的检查器 window 中存在的负载相同,即: 我开始怀疑它的编码不正确。我注意到浏览器调用使用 header ..当我尝试复制这个或任何单一类型(除了 br)时,我仍然收到相同的消息,但以 VBA 当地人 window 无法理解的格式回复。我在其他 POST 和 PUT 请求中取得了成功,无需指定 Accept-Encoding 即可发送 JSON 或文本有效负载,因此我不确定这是否是继续前进的正确路径。 如果有人能够提供一些帮助,我将非常感激。 谢谢!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
------WebKitFormBoundaryeeYChAY7UlBEI63d
Content-Disposition: form-data; name="file"; filename="Test.txt"
Content-Type: text/plain
TestContents
------WebKitFormBoundaryeeYChAY7UlBEI63d
Content-Disposition: form-data; name="material"
16145
------WebKitFormBoundaryeeYChAY7UlBEI63d--
Accept-Encoding: gzip, deflate, br
如果您有标签参数,它将缺少起始边界。
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