尽管有效负载与成功的浏览器发起的请求相同,但通过 HTTPRequest 与 VBA 的“无效的多部分有效负载格式”

     2023-02-19     112

关键词:

【中文标题】尽管有效负载与成功的浏览器发起的请求相同,但通过 HTTPRequest 与 VBA 的“无效的多部分有效负载格式”【英文标题】:"Invalid multipart payload format" via HTTPRequest with VBA despite identical payload to successful browser initiated requests 【发布时间】:2022-01-21 11:45:16 【问题描述】:

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

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

我正在使用以下代码创建多部分有效负载并将其发送到 Web 服务(URL 部分混淆),并使用以下问题帮助重写了几次以解决此问题:[ https://***.com/questions/50110601/upload-a-picture-to-file-io-http-post-in-vba]

(对于内部的任何混乱,我深表歉意 - 我已经更改和重写了很长一段时间了,所以可能会有一些不整洁)

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 的检查器窗口中显示的相同的有效负载,即:

------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

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

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

谢谢!

【问题讨论】:

尝试使用vbCrLF 代替Chr(10) 啊,这是让我感到最简单的事情,这很有魅力,非常感谢!! 【参考方案1】:

感谢 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

【讨论】:

【参考方案2】:

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

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

【讨论】:

很好,谢谢!我在重写时错过了这一点。

说清楚

...代码他俩彼此可以互相独立发出请求拉高;valid拉高时与有效数据同步,时钟要对齐;(valid与有效数据拉高的时钟要对齐,提高效率)当数据计算好后,valid可以拉高等待ready拉高,但是每当握手成功之后,数据需要更新,如果... 查看详情

如何在scrapy中发送带有标头和有效负载的Post请求

】如何在scrapy中发送带有标头和有效负载的Post请求【英文标题】:HowtosendaPostrequestswithheadersandpayloadinscrapy【发布时间】:2021-07-1010:28:23【问题描述】:我正在尝试向GraphAPI发送发布请求,并且我成功了,但我想在scrapy中发送相同... 查看详情

密码在请求有效负载 devtools 中可见

】密码在请求有效负载devtools中可见【英文标题】:Passwordvisibleinrequestpayloaddevtools【发布时间】:2019-01-2313:05:41【问题描述】:使用bcrypt对密码进行哈希处理,并将加密形式的密码保存在数据库中,因为我必须继续操作,以便密... 查看详情

https的页面中可以发起http的请求吗

...策略的定义是这样的:1.协议相同2.域名相同3.端口相同,尽管https访问http确实不符合同源策略中的协议相同,但反过来http页面中可以使用https请求。为什么又可以了,其实这不是同源策略的问题,而是跟混合内容的问题。以下内... 查看详情

汉堡图标:尽管像素对齐,但面包+汉堡的大小相同?

...比其他条高一个像素。这不是因为我的css错误,这是因为浏览器将矩形的边缘与像素网格对齐。我尝试了几种不同的方法来制作汉堡图标:绝对定位一些带有背景颜色的div。内嵌svg标签svg作为背景 查看详情

PDF 表单提交 - 请求有效负载 PHP 解析器

...,并设置了操作按钮以将表单提交到我的服务器的URL。在浏览器中填写表单并点击提交后,它会向URL发送POST请求,但没有任何数据检查网络时,我发现“RequestPayload”里面 查看详情

springcloud系列-2ribbon简介与应用

...址,并将该服务器地址写入HTTP重定向响应中返回给用户浏览器。用户浏览器在获取到响应之后,根据返回的信息,重新发送一个请求到真实的服务器上。DNS服务器解析到IP地址为192.168.8.74,即HTTP重定向服务器的IP地址。重定向服... 查看详情

axios 在 20 秒内给出响应,但具有相同请求负载的相同 api 在 6 秒内从邮递员给出响应

】axios在20秒内给出响应,但具有相同请求负载的相同api在6秒内从邮递员给出响应【英文标题】:axiosisgivingresponsein20sec,butsameapiwithsamerequestpayloadisgivingresponsein6secfrompostman【发布时间】:2019-09-1008:56:45【问题描述】:我正在使用axi... 查看详情

尽管代码相同,但切换菜单按钮在索引页面上有效,但在其他页面上无效 - 为啥?

】尽管代码相同,但切换菜单按钮在索引页面上有效,但在其他页面上无效-为啥?【英文标题】:togglemenubuttonworksonindexpagebutnotonotherpagesdespiteidenticalcode-why?尽管代码相同,但切换菜单按钮在索引页面上有效,但在其他页面上无... 查看详情

2 相同的 HTTP 请求给出不同的结果?

...有什么区别,导致它们从服务器获得不同的结果/响应,尽管它们应该是相同的?Chrome发起简单请求后的请求点击/导航(成功,响应码为302)我只是复制了该请求作为卷曲并将其导入邮递员,然后邮递员绞死我对Java做了同样的事... 查看详情

计算机网络http:http缓存

...中(包括中间一些HTTP代理服务器以及发出请求的客户端浏览器),都可以对返回内容进行缓存操作private代表只有发起请求的浏览器才可以进行缓存no_cache可以在本地进行缓存,但每次发请求时,都有向服务器进行验证,如果服... 查看详情

怎么查看nginx是不是负载均衡

...理后面用户发给的请求同步传输:比如squid代理tomcat时,浏览器发起请求,然后请求会squid立刻被转到后端服务器,于是在浏览器和后端服务器之间就建立了一个连接。在请求发起到请求完成,这条连接都是一直存在的。异步传... 查看详情

rpc异常重试机制详解

...试重试次数RPC异常重试:调用端在发起RPC调用时,会经过负载均衡,选择一个节点,之后它会向这个节点发送请求信息。当消息发送失败或收到异常消息时,即可捕获异常,根据异常触发重试,重新通过负载均衡选择一个节点发... 查看详情

我需要为网站创建帐户生成器,但请求有效负载存在一些问题

】我需要为网站创建帐户生成器,但请求有效负载存在一些问题【英文标题】:Ineedtomakeanaccountgeneratorforasitebutihavesomeproblemswiththerequestpayload【发布时间】:2021-10-2010:29:09【问题描述】:注册窗口需要姓名、姓氏、电子邮件、密码... 查看详情

负载均衡

...将响应消息的状态码设为302,最后将这个响应消息返回给浏览器。当浏览器收到响应消息后,解析Location字段,并向该URL发起请求,然后指定的服务器处理该用户的请求,最后将结果返回给用户。在使用HTTP重定向来实现服务器集... 查看详情

在 Chrome 开发工具网络选项卡中看到的“请求有效负载”与“表单数据”有啥区别

】在Chrome开发工具网络选项卡中看到的“请求有效负载”与“表单数据”有啥区别【英文标题】:What\'sthedifferencebetween"RequestPayload"vs"FormData"asseeninChromedevtoolsNetworktab在Chrome开发工具网络选项卡中看到的“请求有效... 查看详情

尽管在邮递员中工作,但请求 JSON 在 JMeter 中给出错误

】尽管在邮递员中工作,但请求JSON在JMeter中给出错误【英文标题】:RequestJSONgivingerrorinJMeterthoughworksinpostman【发布时间】:2021-10-2709:26:43【问题描述】:我正在尝试在JMeter中对我的一个API进行负载测试。在swagger或postman中测试时... 查看详情

06.nacosfeign负载均衡

...,通过@FeignClient("服务名")注解来指定调用哪个服务通过浏览器访问http://localhost:8080/feign/echo/hi负载主机可以提供很多种负载均衡方法,也就是我们常说的调度方法或算法RoundRobin:这种方法会将收到的请求循环分配到服务器集群... 查看详情