英文:
VBA TalentLMS API Post Request with multipart/form-data throwing error when passing Request Body with boundaries in as a string parameter
问题
我正在创建一个在MS Access中调用TalentLMS API不同端点的模块。我正在创建函数以减少每个端点所需的代码量。到目前为止,所有我的GET请求都正常工作。我也成功地创建了一个用于添加用户帐户的POST请求。我遇到的问题是,如果我在API调用函数中生成multipart/form-data(请求正文),则可以正常工作,但如果我将multipart/form-data(请求正文)作为参数传递给API调用函数,则无法正常工作。
以下是已经正常工作的代码:
' 代码...
以下是不正常工作的代码:
' 代码...
当请求正文生成并作为字符串返回时,它会作为参数传递给下一个函数。
' 代码...
在两种情况下,postData都是一个字符串,它们具有相同的参数。根据TalentLMS API,400错误代码的解释是“缺少必需参数或提供了无效类型(例如字符串)而不是整数”。在这两种情况下,postData都是一个字符串,它们具有相同的参数。
是否有人看到我漏掉了什么?
英文:
I am creating a Module in MS Access to make API calls to different endpoints in the TalentLMS API. I am creating functions to minimize the code needed for each endpoint. So far all of my GET requests are working. I have a POST request to add a user account working as well. The problem that I am running into is that I have a POST request to delete a user account that works if I generate the multipart/form-data (Request Body) in the API Call function but does not work if I pass the mutlipart/form-data (Request Body) in as a parameter to the API Call function.
This is Working I generate the request body with boundaries within the API call function as a string.
<!-- language: vb -->
Function talentAPICall_3(ByVal intUserid As Integer, ByVal strPermanent As String) As String
Dim request As New MSXML2.XMLHTTP30
Dim apiURL, boundary, postData, strRequest, strResponse As String
Dim contentLen As Long
apiURL = "https://<<myDomain>>.talentlms.com/api/v1/"
strRequest = apiURL & "deleteuser/"
boundary = "----------------------------" & Format(Now, "ddmmyyyyhhmmss")
postData = "--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""user_id""" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf & _
intUserid & vbCrLf & _
"--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""permanent""" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf & _
strPermanent & vbCrLf & _
"--" & boundary & "--"
contentLen = Len(postData)
With request
.Open "POST", (strRequest), False
.setRequestHeader "Authorization", "Basic <<MyAPIKey>>=="
.setRequestHeader "Host", "<<myDomain>>.talentlms.com"
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary
.setRequestHeader "content-Length", contentLen
.send (postData)
While request.ReadyState <> 4
DoEvents
Wend
strResponse = .responseText
End With
Debug.Print "Server responded with status " & request.statusText & " - code: "; request.status
Debug.Print postData
talentAPICall_3 = strResponse
End Function
This is NOT Working Where I use a getBoundaries() function to pass the body request with boundaries as a string to the API call function.
Function DelUser(ByVal intUserid As Integer, ByVal strPermanent As String) As String
Dim postData, strResponse As String
Dim boundaries() As Variant
boundaries = Array("user_id", intUserid, "permanent", strPermanent)
postData = getBoundaries(boundaries)
strResponse = talentAPICall_4(postData)
DelUser = strResponse
End Function
Which calls the following.
Function getBoundaries(params() As Variant) As String
Dim boundary, boundaries As String
boundary = "----------------------------" & Format(Now, "ddmmyyyyhhmmss")
Dim i As Long
boundaries = ""
For i = LBound(params) To UBound(params)
boundaries = boundaries & "--" & boundary & vbCrLf & _
"Content-Disposition: form-data; name=""" & params(i) & """" & vbCrLf & _
"Content-Type: text/plain; charset=UTF-8" & vbCrLf & vbCrLf
i = i + 1
boundaries = boundaries & params(i) & vbCrLf
Next i
boundaries = boundaries & "--" & boundary & "--"
getBoundaries = boundaries
End Function
When the Request Body is generated with boundaries and returned as a string, it is then passed as a parameter to the next function.
Function talentAPICall_4(ByVal postData As String) As String
Dim request As New MSXML2.XMLHTTP30
Dim apiURL, boundary, strRequest, strResponse As String
Dim contentLen As Long
apiURL = "https://<<myDomain>>.talentlms.com/api/v1/"
strRequest = apiURL & "deleteuser/"
boundary = Left(postData, 44)
contentLen = Len(postData)
With request
.Open "POST", (strRequest), False
.setRequestHeader "Authorization", "Basic <<MyAPIKey>>=="
.setRequestHeader "Host", "<<myDomain>>.talentlms.com"
.setRequestHeader "Content-Type", "multipart/form-data; boundary=" & boundary
.setRequestHeader "content-Length", contentLen
.send (postData)
While request.ReadyState <> 4
DoEvents
Wend
strResponse = .responseText
End With
Debug.Print "Server responded with status " & request.statusText & " - code: "; request.status
Debug.Print postData
talentAPICall_4 = strResponse
End Function
Here are the results of both methods used:
Working:
call talentAPICall_3(3314, "yes")
Server responded with status OK - code: 200
Posted Data:
------------------------------15022023131313
Content-Disposition: form-data; name="user_id"
Content-Type: text/plain; charset=UTF-8
3314
------------------------------15022023131313
Content-Disposition: form-data; name="permanent"
Content-Type: text/plain; charset=UTF-8
yes
------------------------------15022023131313--
Not Working:
call delUser(3314, "yes")
Server responded with status Bad Request - code: 400
Posted Data:
------------------------------15022023131246
Content-Disposition: form-data; name="user_id"
Content-Type: text/plain; charset=UTF-8
3314
------------------------------15022023131246
Content-Disposition: form-data; name="permanent"
Content-Type: text/plain; charset=UTF-8
yes
------------------------------15022023131246--
As you can see, except for the variation of the time stamp used to create the boundary, the postData from Debug.Print for both functions is the same. The TalentLMS API states that the following for the 400 error code "A required parameter is missing or an invalid type (e.g. a string) was supplied instead of an integer." In both cases postData is a String and they have the same parameters.
Anyone see what I am missing?
答案1
得分: 0
在你的“工作”代码中,边界头的长度为42,而在不工作的代码中,长度为44?
你需要移除开头的“--”...
boundary = Mid(postData, 3, 42)
可能更安全将边界传递给 getBoundaries
而不是尝试从输出中提取它。
英文:
In your "working" code the boundary header length is 42, and in the non-working code it's 44?
You need to remove the leading "--"...
boundary = Mid(postData, 3, 42)
Might be safer to pass the boundary in to getBoundaries
rather than try to extract it from the output.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论