App下載

如何使用Go和AzureFunctions來構(gòu)建無服務器應用程序?方法分享!

一顆跳動的心 2021-09-16 14:32:46 瀏覽數(shù) (2083)
反饋

Webhook 后端是 FaaS(功能即服務)平臺的流行用例。它們可用于許多用例,例如發(fā)送客戶通知以使用有趣的 GIF 進行響應!使用 Serverless 功能,封裝 webhook 功能并以 HTTP 端點的形式公開它非常方便。在本文章中,你將學習如何使用Azure FunctionsGoSlack 應用實現(xiàn)為無服務器后端。您可以通過實施自定義應用程序或工作流來擴展 Slack 平臺并集成服務,這些應用程序或工作流可以訪問平臺的全部范圍,從而允許您在 Slack 中構(gòu)建強大的體驗。

這是SlackGiphy的更簡單版本。最初的 Giphy Slack 應用程序通過響應多個 GIF 來響應搜索請求。為簡單起見,本文中演示的函數(shù)應用程序僅使用Giphy Random API返回與搜索關鍵字對應的單個(隨機)圖像。這篇博文提供了將應用程序部署到Azure Functions并將其與 Slack 工作區(qū)集成的分步指南。

在這篇文章中,您將:

  • 了解Azure Functions 中自定義處理程序
  • 通過簡短的代碼演練了解幕后發(fā)生的事情
  • 了解如何使用配置 Azure Functions 和 Slack 設置解決方案
  • 當然,在工作區(qū)中運行您的 Slack 應用程序!

后端函數(shù)邏輯是用 Go 編寫的(代碼可在 GitHub 上找到。使用過 Azure Functions 的人可能還記得 Go不是默認支持的語言處理程序之一。這就是自定義處理程序來救援的地方!

什么是自定義處理程序?

簡而言之,自定義處理程序是一個輕量級的 Web 服務器,它接收來自 Functions 主機的事件。在您最喜歡的運行時/語言中實現(xiàn)自定義處理程序唯一需要的是:HTTP 支持!這并不意味著自定義處理程序僅限于HTTP 觸發(fā)器- 您可以通過擴展包自由使用其他觸發(fā)器以及輸入和輸出綁定。

這是自定義處理程序如何在高層工作的摘要(下圖摘自文檔)

事件觸發(fā)器(通過 HTTP、存儲、事件中心等)調(diào)用 Functions 主機。該辦法自定義處理程序從傳統(tǒng)的功能不同的是,該功能的主機充當中間人:它有一個沿發(fā)出請求負載到自定義處理程序(功能)的Web服務器負載包含觸發(fā)器,輸入數(shù)據(jù)綁定,等函數(shù)的元數(shù)據(jù)。該函數(shù)將響應返回給 Functions 主機,該主機將數(shù)據(jù)從響應傳遞到函數(shù)的輸出綁定以進行處理。

概述

在我們深入研究其他領域之前,通過探索代碼(順便說一下相對簡單)可能有助于理解本質(zhì)

應用結(jié)構(gòu)

讓我們看看應用程序是如何設置的。這是在文檔中定義的

java:

├── cmd
│   └── main.go
├── funcy
│   └── function.json
├── go.mod
├── host.json
└── pkg
    └── function
        ├── function.go
        ├── giphy.go
        └── slack.go

該function.json文件位于一個文件夾中,其名稱按照慣例用作函數(shù)名稱。

java:

{
    "bindings": [
        {
            "type": "httpTrigger",
            "direction": "in",
            "name": "req",
            "methods": [
                "get",
                "post"
            ]
        },
        {
            "type": "http",
            "direction": "out",
            "name": "res"
        }
    ]
}

host.json通過指向能夠處理 HTTP 事件的 Web 服務器,告訴 Functions 主機將請求發(fā)送到何處。注意  customHandler.description.defaultExecutablePath,它定義了go_funcy將用于運行網(wǎng)絡服務器的可執(zhí)行文件的名稱。"enableForwardingHttpRequest": true確保將原始 HTTP 數(shù)據(jù)發(fā)送到自定義處理程序而無需任何修改。

java:

{
    "version": "2.0",
    "extensionBundle": {
        "id": "Microsoft.Azure.Functions.ExtensionBundle",
        "version": "[1.*, 2.0.0)"
    },
    "customHandler": {
        "description": {
            "defaultExecutablePath": "go_funcy"
        },
        "enableForwardingHttpRequest": true
    },
    "logging": {
        "logLevel": {
            "default": "Trace"
        }
    }
}

該cmd和pkg目錄包含圍棋源代碼。讓我們在下一個小節(jié)中探討這一點。

代碼演練

cmd/main.go設置并啟動 HTTP 服務器。請注意,/api/funcy端點是 Function 主機向自定義處理程序 HTTP 服務器發(fā)送請求的端點。

java:

func main() {
    port, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
    if !exists {
        port = "8080"
    }
    http.HandleFunc("/api/funcy", function.Funcy)
    log.Fatal(http.ListenAndServe(":"+port, nil))
}

所有繁重的工作都在function/function.go.

第一部分是讀取請求正文(來自 Slack)并通過基于Slack 定義的配方的簽名驗證過程確保其完整性。

java:

  signingSecret := os.Getenv("SLACK_SIGNING_SECRET")
    apiKey := os.Getenv("GIPHY_API_KEY")
    if signingSecret == "" || apiKey == "" {
        http.Error(w, "Failed to process request. Please contact the admin", http.StatusUnauthorized)
        return
    }
    slackTimestamp := r.Header.Get("X-Slack-Request-Timestamp")
    b, err := ioutil.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Failed to process request", http.StatusBadRequest)
        return
    }
    slackSigningBaseString := "v0:" + slackTimestamp + ":" + string(b)
    slackSignature := r.Header.Get("X-Slack-Signature")
    if !matchSignature(slackSignature, signingSecret, slackSigningBaseString) {
        http.Error(w, "Function was not invoked by Slack", http.StatusForbidden)
        return
    }

一旦我們確認該函數(shù)確實是通過 Slack 調(diào)用的,下一部分是提取 (Slack) 用戶輸入的搜索詞。

java:

 vals, err := parse(b)
    if err != nil {
        http.Error(w, "Failed to process request", http.StatusBadRequest)
        return;
    }
    giphyTag := vals.Get("text")

通過調(diào)用 GIPHY REST API 使用搜索詞查找 GIF。

java:

    giphyResp, err := http.Get("http://api.giphy.com/v1/gifs/random?tag=" + giphyTag + "&api_key=" + apiKey)
    if err != nil {
        http.Error(w, "Failed to process request", http.StatusFailedDependency)
        return
    }
    resp, err := ioutil.ReadAll(giphyResp.Body)
    if err != nil {
        http.Error(w, "Failed to process request", http.StatusInternalServerError)
        return
    }

解組 GIPHY API 發(fā)回的響應,將其轉(zhuǎn)換為 Slack 可以理解的形式,然后返回。就是這樣!

java:

    var gr GiphyResponse
    json.Unmarshal(resp, &gr)
    title := gr.Data.Title
    url := gr.Data.Images.Downsized.URL
    slackResponse := SlackResponse{Text: slackResponseStaticText, Attachments: []Attachment{{Text: title, ImageURL: url}}}
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(slackResponse)
    fmt.Println("Sent response to Slack")

matchSignature如果您對檢查簽名驗證過程感興趣,請檢查該函數(shù),并查看 slack.go、giphy.go(在function目錄中)以查看所使用的 Go 結(jié)構(gòu)體表示在各個組件之間交換的信息(JSON)。為了保持這篇文章的簡潔性,這里沒有包含這些內(nèi)容。

好的,到目前為止,我們已經(jīng)介紹了很多理論和背景信息。是時候把事情做好了!在繼續(xù)之前,請確保您滿足以下提到的先決條件。

先決條件

  • 如果您還沒有Go,請下載并安裝它。
  • 安裝Azure Functions Core Tools    ? 這將允許您使用 CLI 部署該函數(shù)(并且還可以在本地運行它進行測試和調(diào)試)。
  • 如果沒有,請創(chuàng)建一個 Slack 工作區(qū)。
  • 獲取 GIPHY API 密鑰 - 您需要創(chuàng)建一個 GIHPY 帳戶(它是免費的!)并創(chuàng)建一個應用程序。您創(chuàng)建的每個應用程序都有自己的 API 密鑰。
請復制您的 GIPHY API 密鑰,因為您稍后將使用它。

接下來的部分將指導您完成部署 Azure 函數(shù)和為 Slash 命令配置 Slack 的過程。

Azure 函數(shù)設置

首先創(chuàng)建一個資源組來托管解決方案的所有組件。

創(chuàng)建函數(shù)應用

  1. 首先在 Azure 門戶中搜索Function App,然后單擊添加。
  2. 輸入所需的詳細信息:您應該選擇自定義處理程序作為運行時堆棧。
  3. 在Hosting部分,分別為操作系統(tǒng)和計劃類型選擇Linux和Consumption (Serverless)。
  4. 啟用 Application Insights(如果需要)。
  5. 查看最終設置并單擊創(chuàng)建以繼續(xù)。
  6. 該過程完成后,還將與 Function App 一起創(chuàng)建以下資源:

部署函數(shù)

克隆 GitHub 存儲庫并構(gòu)建函數(shù)。

java:

git clone https://github.com/abhirockzz/serverless-go-slack-app
cd serverless-go-slack-app
GOOS=linux go build -o go_funcy cmd/main.go

GOOS=linux用于構(gòu)建Linux可執(zhí)行文件,因為我們Linux為 Function App選擇了操作系統(tǒng)。

若要部署,請使用 Azure Functions 核心工具 CLI。

java:

func azure functionapp publish <enter name of the function app>

部署后,復制命令 ? 返回的函數(shù) URL,您將在后續(xù)步驟中使用它。

配置松弛

本節(jié)將介紹在工作區(qū)中設置 Slack 應用程序(Slash 命令)所需執(zhí)行的步驟:

  • 創(chuàng)建一個 Slack 應用程序。
  • 創(chuàng)建斜線命令。
  • 將應用程序安裝到您的工作區(qū)。

創(chuàng)建 Slack 應用程序和 Slash 命令

登錄到您的Slack 工作區(qū)并開始創(chuàng)建一個新的 Slack 應用程序。

單擊“創(chuàng)建新命令”以使用所需信息定義新的斜線命令。請注意,請求 URL字段是您將輸入函數(shù)的 HTTP 端點的字段,它只是您在上一節(jié)中部署函數(shù)后獲得的 URL。完成后,點擊保存完成。

將應用程序安裝到您的工作區(qū)

完成 Slash 命令的創(chuàng)建后,前往應用程序的設置頁面,單擊導航菜單中的基本信息功能,選擇將應用程序安裝到工作區(qū), 然后單擊將應用程序安裝到工作區(qū)? 這會將應用程序安裝到您的工作區(qū)  用于測試您的應用程序并生成與 Slack API 交互所需的令牌的 Slack 工作區(qū)。應用程序安裝完成后,應用程序憑據(jù)將顯示在同一頁面上。

記下您的應用簽名密鑰,因為您稍后將使用它。

在你進入有趣的部分之前

確保更新 Function App 配置以添加 Slack Signing Secret ( SLACK_SIGNING_SECRET) 和 Giphy API 密鑰 ( GIPHY_API_KEY) ? 它們將作為函數(shù)內(nèi)的環(huán)境變量可用。

FUN(cy)時間!

我們可以從你的 Slack 工作區(qū),調(diào)用命令/funcy <search term>. 例如嘗試/funcy dog。

你應該拿回一個隨機的 GIF 作為回報!

簡單回顧一下正在發(fā)生的事情:當您/funcy在 Slack 中調(diào)用命令時,它會調(diào)用該函數(shù),然后與 Giphy API 交互并最終將 GIF 返回給用戶(如果一切順利)。

您可能會timeout error在第一次調(diào)用后從 Slack 中看到。這很可能是因為cold start該函數(shù)在第一次調(diào)用時需要幾秒鐘的時間來引導。這與Slack 期望在 3 秒內(nèi)得到響應的事實相結(jié)合,給出了錯誤消息。

沒有什么可擔心的。您所需要的只是重試,一切都會好起來的!

清理

當我們在完成后這個測試之后不要忘記刪除資源組,就是將刪除之前創(chuàng)建的所有資源(功能應用、應用服務計劃等)。 

結(jié)論

沒有什么能阻止您在 Azure 上使用 Go 實現(xiàn)無服務器功能!我希望這是一種嘗試自定義處理程序的有趣方式。


0 人點贊