VBA實戰 - 一個簡單的 httplib

概要

VBA 的應用場景基本都仍是在單機應用, 隨着 Web 應用的風靡, 以及瀏覽器愈來愈強大, 單機類的應用逐漸沒落.git

雖然 Web 應用愈來愈多, 功能和體驗也愈來愈好, 可是 Excel 依然有很強的生命力, 畢竟 Web 頁面上的表格再強大, 也沒有 Excel 那麼方便易用.github

Excel 通過這麼多年的積累, 不只有很大的用戶基礎, 對錶格類數據的處理幾乎已經到極致.
若是可以以 Excel 自己做爲 UI, 經過 VBA 來鏈接 Excel 和後端服務, 使它成爲 Web 頁面的輔助, 而不是強行在 Web 頁面實現 Excel 表格的各類功能, 應該能有事半功倍的效果.golang

先後端分離已是目前的主流, 只要可以經過 VBA 訪問後端的 API, 並解析後端返回的數據(通常是 JSON 格式), 就能讓 Excel 成爲 Web 頁面的輔助, 高效的處理表格類數據.json

VBA httplib 庫的簡單實現

爲了能和後端 API 交互, 須要實現一個簡單的 httplib 庫, 便於在各個 VBA 工程中複用.後端

根據目前本身的需求, 這個簡單的 httplib 庫暫時完成如下幾個功能:瀏覽器

  1. 可以發送 GET 請求
  2. 可以發送 POST 請求
  3. 可以解析請求返回的 JSON 數據
  4. POST 請求中能夠帶 JSON 格式的參數
  5. 請求的 header 中能夠加入 jwt token 信息

環境準備

爲了測試 httplib, 用 golang 的 gin 框架簡單實現了一個 http API 服務. 代碼參見文後的 附錄一緩存

httplib 主要實現了 get/post 訪問 API, 參數和返回值都是 json 格式字符串. 代碼參見文後的 附錄二cors

下面的測試主要演示如何使用 httplib :框架

發送 GET 請求

1  Function testGet()
 2      Dim hlib As New HttpLib
 3      Dim ret As Boolean
 4  
 5      hlib.SetUrl = "http://localhost:8000/get-test"
 6      ret = hlib.HttpGetJSON("")
 7      Debug.Print ret
 8      If ret = True Then
 9          Debug.Print hlib.GetJSONResp
10      End If
11  End Function

SetUrl 以後, 調用 HttpGetJSON 便可
運行結果以下:前後端分離

True
{"message":"get success"}

發送 POST 請求

1  Function testPost()
 2      Dim hlib As New HttpLib
 3      Dim ret As Boolean
 4  
 5      hlib.SetUrl = "http://localhost:8000/post-test"
 6      ret = hlib.HttpPostJSON("")
 7      Debug.Print ret
 8      If ret = True Then
 9          Debug.Print hlib.GetJSONResp
10      End If
11  End Function

SetUrl 以後, 調用 HttpPostJSON 便可
運行結果以下:

True
{"message":"post success"}

解析請求返回的 JSON 數據

要解析返回的 JSON 數據, 這裏藉助另一個 VBA 模塊: VBA-JSON

1  Function testPostWithReturn()
 2  
 3      Dim hlib As New HttpLib
 4      Dim ret As Boolean
 5  
 6      hlib.SetUrl = "http://localhost:8000/post-test-return"
 7      ret = hlib.HttpPostJSON("")
 8      Debug.Print ret
 9      If ret = True Then
10          Dim resp As Object
11          Set resp = JsonConverter.ParseJson(hlib.GetJSONResp)
12          Debug.Print "response json: " & hlib.GetJSONResp
13          Debug.Print "username: " & resp("username")
14          Debug.Print "data -> list 1: " & resp("data")("list")(1)
15          Debug.Print "data -> list 2: " & resp("data")("list")(2)
16          Debug.Print "data -> list 3: " & resp("data")("list")(3)
17      End If
18  End Function

在使用 VBA-JSON 庫的時候, 須要添加引用 Microsoft Scripting Runtime

添加的方法, 在 VBA 編輯器中 選擇 "工具" -> "引用" -> 添加 "Microsoft Scripting Runtime"

運行結果以下:

True
response json: {"data":{"list":["a","b","c"]},"username":"string"}
username: string
data -> list 1: a
data -> list 2: b
data -> list 3: c

POST 請求中帶 JSON 格式的參數

1  Function testPostWithParam()
 2  
 3      Dim hlib As New HttpLib
 4      Dim ret As Boolean
 5      Dim p As Dictionary
 6      Set p = New Dictionary
 7  
 8      hlib.SetUrl = "http://localhost:8000/post-test-param"
 9      p("name") = "name"
10      p("data") = Array("a", "b", "c")
11  
12      ret = hlib.HttpPostJSON(JsonConverter.ConvertToJson(p))
13      Debug.Print ret
14      If ret = True Then
15          Debug.Print "response json: " & hlib.GetJSONResp
16      End If
17  End Function

在服務端的 log 中, 能夠看到, 執行後獲取到了傳遞的參數

2019/10/09 12:14:38 param: struct { Name string "json:\"name\""; Data []string "json:\"data\"" }{Name:"name", Data:[]string{"a", "b", "c"}}

請求的 header 中加入 jwt token 信息

請求中 header 加入信息很簡單, 在 httplib 庫中的 HttpGetJSONHttpPostJSON 方法中都有:

1  http.setRequestHeader "Content-Type", "text/json"
2  http.setRequestHeader "If-Modified-Since", "0"  ' 清除緩存
3  If jwtToken <> "" Then
4      http.setRequestHeader "Authorization", "Bearer " & jwtToken
5  End If

附錄

附錄一 測試用服務端(by golang)

1  package main
 2  
 3  import (
 4   "log"
 5   "net/http"
 6  
 7   "github.com/gin-contrib/cors"
 8   "github.com/gin-gonic/gin"
 9  )
10  
11  func StartGinServ() {
12   r := gin.Default()
13   r.Use(cors.Default())
14  
15   r.GET("/get-test", func(c *gin.Context) {
16     c.JSON(http.StatusOK, gin.H{
17       "message": "get success",
18     })
19   })
20  
21   r.POST("/post-test", func(c *gin.Context) {
22     c.JSON(http.StatusOK, gin.H{
23       "message": "post success",
24     })
25   })
26  
27   var list = []string{"a", "b", "c"}
28   r.POST("/post-test-return", func(c *gin.Context) {
29     c.JSON(http.StatusOK, gin.H{
30       "username": "string",
31       "data": gin.H{
32         "list": list,
33       },
34     })
35   })
36  
37   r.POST("/post-test-param", func(c *gin.Context) {
38     var param struct {
39       Name string   `json:"name"`
40       Data []string `json:"data"`
41     }
42  
43     if err := c.BindJSON(&param); err != nil {
44       log.Fatal("param error")
45     }
46  
47     log.Printf("param: %#v\n", param)
48  
49     c.JSON(http.StatusOK, gin.H{
50       "message": "post with param",
51     })
52   })
53  
54   if err := r.Run(":8000"); err != nil {
55     log.Fatal(err)
56   }
57  
58  }

附錄二 完整的 httplib 庫

1  Option Explicit
 2  
 3  Const ClsName = "lib for http request"
 4  
 5  ' 請求的URL
 6  Dim url As String
 7  ' API認證用的 jwt token
 8  Dim jwtToken As String
 9  ' API返回的json格式結果
10  Dim jsonResp As String
11  
12  ' 設置 URL 屬性
13  Public Property Let SetUrl(p As String)
14      url = p
15  End Property
16  
17  ' 獲取 URL 屬性
18  Public Property Get GetUrl() As String
19      GetUrl = url
20  End Property
21  
22  ' 設置 jwt token 屬性
23  Public Property Let SetJwtToken(p As String)
24      jwtToken = p
25  End Property
26  
27  ' 獲取 jwt token 屬性
28  Public Property Get GetJwtToken() As String
29      GetJwtToken = jwtToken
30  End Property
31  
32  ' 獲取 json response 屬性
33  Public Property Get GetJSONResp() As String
34      GetJSONResp = jsonResp
35  End Property
36  
37  ' TODO 登陸操做, 登陸成功後, 設置 jwt token
38  Function Login(user As String, pwd As String) As Boolean
39      ' TODO 這裏能夠根據具體的登陸實現方式來實現
40      '      登陸成功後, 設置 jwtToken 屬性
41      Login = False
42  End Function
43  
44  ' GET 方式訪問 API
45  Function HttpGetJSON(jsonStr As String) As Boolean
46      HttpGetJSON = False
47      jsonResp = ""
48  
49      Dim http
50      Set http = CreateObject("Msxml2.XMLHTTP")
51      http.Open "GET", url, False
52  
53      ' 設置headers
54      http.setRequestHeader "Content-Type", "text/json"
55      http.setRequestHeader "If-Modified-Since", "0"  ' 清除緩存
56      If jwtToken <> "" Then
57          http.setRequestHeader "Authorization", "Bearer " & jwtToken
58      End If
59  
60      http.send jsonStr
61  
62      If http.Status = 200 Then
63          jsonResp = http.responseText
64          HttpGetJSON = True
65      End If
66  
67  End Function
68  
69  ' POST 方式訪問 API
70  Function HttpPostJSON(jsonStr As String) As Boolean
71      HttpPostJSON = False
72      jsonResp = ""
73  
74      Dim http
75      Set http = CreateObject("Msxml2.XMLHTTP")
76      http.Open "POST", url, False
77  
78      http.setRequestHeader "Content-Type", "text/json"
79      http.setRequestHeader "If-Modified-Since", "0"  ' 清除緩存
80      If jwtToken <> "" Then
81          http.setRequestHeader "Authorization", "Bearer " & jwtToken
82      End If
83  
84      http.send jsonStr
85  
86      If http.Status = 200 Then
87          jsonResp = http.responseText
88          HttpPostJSON = True
89      End If
90  End Function
相關文章
相關標籤/搜索