首页 > 解决方案 > 通过 VBA 访问 REST API 会返回“无效 ID/密钥”错误

问题描述

我正在尝试通过 VBA 代码访问 Appointments-Plus.com API,并且一直被告知我给它一个无效的站点 ID/密钥。我正在使用 Office365 版本的 Access。

这是此 API 调用的相关文档。

当我使用 Postman 测试 API 时,我能够成功连接并取回数据。邮递员放在一起的 URL 是这样的:

https://ws.appointment-plus.com/Locations/GetLocations?Authorization:Basic=<site-ID>:<Key>&response_type=xml

我的 VBA 代码是这样的:

Public Sub RESTtestBigURL()

  Dim responseType As String
  responseType = "response_type=json"

  Dim restRequest As WinHttp.WinHttpRequest
  Set restRequest = New WinHttp.WinHttpRequest

  Dim restResult As String

  With restRequest
    .Open "POST", "https://ws.appointment-plus.com/Locations/GetLocations?Authorization:Basic=<site-ID>:<Key>&response_type=xml", False
    .Send
    .WaitForResponse
    Debug.Print ".ResponseText: " & .ResponseText
    Debug.Print ".Status: " & .Status
    Debug.Print ".StatusText: " & .StatusText
    Debug.Print ".ResponseBody: " & .ResponseBody
  End With

End Sub

我知道第一个问题是“你确定你有正确的吗<site-ID>???<key>” 是的 - 我已经将 Postman 的整个 URL 复制/粘贴到我的 VBA 代码中,并且我已经让另外几对眼球检查它以确认它们仍然相同。

当我运行该代码时,我得到:

.ResponseText: <?xml version="1.0" encoding="utf-8" ?>
<APResponse>
  <resource>customers</resource>
  <action>getcustomers</action>
  <request></request>
  <result>fail</result>
  <count>0</count>
  <errors>
    <error><![CDATA[Web Services authentication failed: invalid Site ID or API Key]]></error>
  </errors>
</APResponse>

我尝试了其他几种访问 API 的方法,所有这些方法都给了我相同的“无效 ID/密钥”错误:

Public Sub SecondRESTtestMSXML()

  Dim restRequest As MSXML2.XMLHTTP60
  Set restRequest = New MSXML2.XMLHTTP60

  With restRequest

    .Open "GET", URL & REQUEST_GET_LOCATIONS, True
    .SetRequestHeader "Authorization", "Basic" & SITE_ID & ":" & API_KEY
    .SetRequestHeader "response_type", "xml"
    .SetRequestHeader "Accept-Encoding", "application/xml"
    .Send "{""response_type"":""JSON""&""location"":""582""}"
    While .ReadyState <> 4
      DoEvents
    Wend
    Debug.Print ".ResponseText: " & .ResponseText
    Debug.Print ".Status: " & .Status
    Debug.Print ".StatusText: " & .StatusText
    Debug.Print ".ResponseBody: " & .ResponseBody

  End With

End Sub

有人建议这是与 Base64 编码解决的另一个问题的重复。但是,这种方法虽然不是很明确,但表明我也尝试过。我添加了Base64Encode从这里调用的函数代码。

Public Sub RESTtest()

  Dim restRequest As WinHttp.WinHttpRequest
  Set restRequest = New WinHttp.WinHttpRequest

  Dim restResult As String

  With restRequest
    .Open "POST", URL & REQUEST_GET_LOCATIONS, True
    .SetRequestHeader "Authorization", "Basic " & SITE_ID & ":" & Base64Encode(API_KEY)
' Note call to Base64Encode() on this line ---------------- ----- ^^^^^^^^^^^^
    .Option(WinHttpRequestOption_EnableRedirects) = False
    .Send "{""response_type"":""JSON""}"
    .WaitForResponse
    Debug.Print ".ResponseText: " & .ResponseText
    Debug.Print ".Status: " & .Status
    Debug.Print ".StatusText: " & .StatusText
    Debug.Print ".ResponseBody: " & .ResponseBody
  End With

End Sub

Public Function Base64Encode(ByVal inputText As String) As String
  Dim xmlDoc As Object
  Dim docNode As Variant
  Set xmlDoc = CreateObject("Msxml2.DOMDocument.3.0")
  Set docNode = xmlDoc.createElement("base64")
  docNode.DataType = "bin.base64"
  docNode.nodeTypedValue = Stream_StringToBinary(inputText)
  Base64Encode = docNode.Text
  Set docNode = Nothing
  Set xmlDoc = Nothing
End Function

笔记:

是否有人在此代码中看到任何明显的错误?对尝试调用 API 并获得结果的其他方法有什么建议吗?我曾建议用 C# 编写一个 DLL 并调用它,但是,我没有时间学习足够的 C# 来实现这一点,因此在这里切换语言并不是一个真正的选择。

补充说明:

curl我在 Powershell 会话中尝试了这个,它给了我相同的结果:

PS H:\> curl -method Post -uri "https://ws.appointment-plus.com/Locations/GetLocations?Authorization:Basic=<ID>:<key>&response_type=json"

结果:

StatusCode        : 200
StatusDescription : OK
Content           : {"resource":"locations",
                     "action":"getlocations",
                     "request":"",
                     "result":"fail",
                     "count":"0"
                    ,"errors":[
                        "Web Services authentication failed: invalid Site ID or API ...
RawContent        : HTTP/1.1 200 OK
                    Pragma: no-cache
                    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
                    Date: Mon, 26 Aug 2019 17:28:41 GMT
                    Expires: Thu, 19 Nov 1981 08:52:00 GMT
                    Set-Cooki...
Forms             : {}
Headers           : {[Pragma, no-cache], [Cache-Control, no-store, no-cache, must-revalidate, post-check=0,
                    pre-check=0], [Date, Mon, 26 Aug 2019 17:28:41 GMT], [Expires, Thu, 19 Nov 1981 08:52:00 GMT]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 207

标签: vbarestapims-access

解决方案


根据评论中的交流,主要问题似乎是基本授权标头是如何形成的。

对于未来的读者,授权标头的格式为:

.SetRequestHeader "Authorization", "Basic " & Base64Encode(SITE_ID & ":" & API_KEY)

此外,您可能遇到的另一个问题与此处有关。使用当前方法将换行符插入到 Base64 编码的字符串中,这对于大多数(如果不是全部)API 来说都不是很好。建议的解决方法如下:

Public Function Base64Encode(ByVal inputText As String, Optional removeBlankLines = True) As String
    Dim xmlDoc As Object
    Dim docNode As Variant
    Set xmlDoc = CreateObject("Msxml2.DOMDocument.3.0")
    Set docNode = xmlDoc.createElement("base64")
    docNode.DataType = "bin.base64"
    docNode.nodeTypedValue = Stream_StringToBinary(inputText)
    Base64Encode = docNode.Text
    Set docNode = Nothing
    Set xmlDoc = Nothing

    'remove blank line characters ASCII --> 10,13,10 + 13
    If removeBlankLines Then Base64Encode = Replace(Replace(Replace(Base64Encode, vbCrLf, vbNullString), vbLf, vbNullString), vbCr, vbNullString)
End Function

推荐阅读