App下載

如何使用Go和AzureFunctions來(lái)構(gòu)建無(wú)服務(wù)器應(yīng)用程序?方法分享!

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

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

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

在這篇文章中,您將:

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

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

什么是自定義處理程序?

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

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

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

概述

在我們深入研究其他領(lǐng)域之前,通過(guò)探索代碼(順便說(shuō)一下相對(duì)簡(jiǎn)單)可能有助于理解本質(zhì)

應(yīng)用結(jié)構(gòu)

讓我們看看應(yīng)用程序是如何設(shè)置的。這是在文檔中定義的

java:

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

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

java:

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

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

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目錄包含圍棋源代碼。讓我們?cè)谙乱粋€(gè)小節(jié)中探討這一點(diǎn)。

代碼演練

cmd/main.go設(shè)置并啟動(dòng) HTTP 服務(wù)器。請(qǐng)注意,/api/funcy端點(diǎn)是 Function 主機(jī)向自定義處理程序 HTTP 服務(wù)器發(fā)送請(qǐng)求的端點(diǎn)。

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.

第一部分是讀取請(qǐng)求正文(來(lái)自 Slack)并通過(guò)基于Slack 定義的配方的簽名驗(yàn)證過(guò)程確保其完整性。

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
    }

一旦我們確認(rèn)該函數(shù)確實(shí)是通過(guò) 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")

通過(guò)調(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ā)回的響應(yīng),將其轉(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如果您對(duì)檢查簽名驗(yàn)證過(guò)程感興趣,請(qǐng)檢查該函數(shù),并查看 slack.go、giphy.go(在function目錄中)以查看所使用的 Go 結(jié)構(gòu)體表示在各個(gè)組件之間交換的信息(JSON)。為了保持這篇文章的簡(jiǎn)潔性,這里沒(méi)有包含這些內(nèi)容。

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

先決條件

  • 如果您還沒(méi)有Go,請(qǐng)下載并安裝它。
  • 安裝Azure Functions Core Tools    ? 這將允許您使用 CLI 部署該函數(shù)(并且還可以在本地運(yùn)行它進(jìn)行測(cè)試和調(diào)試)。
  • 如果沒(méi)有,請(qǐng)創(chuàng)建一個(gè) Slack 工作區(qū)。
  • 獲取 GIPHY API 密鑰 - 您需要?jiǎng)?chuàng)建一個(gè) GIHPY 帳戶(它是免費(fèi)的?。┎?chuàng)建一個(gè)應(yīng)用程序。您創(chuàng)建的每個(gè)應(yīng)用程序都有自己的 API 密鑰。
請(qǐng)復(fù)制您的 GIPHY API 密鑰,因?yàn)槟院髮⑹褂盟?/blockquote>

接下來(lái)的部分將指導(dǎo)您完成部署 Azure 函數(shù)和為 Slash 命令配置 Slack 的過(guò)程。

Azure 函數(shù)設(shè)置

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

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

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

部署函數(shù)

克隆 GitHub 存儲(chǔ)庫(kù)并構(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í)行文件,因?yàn)槲覀僉inux為 Function App選擇了操作系統(tǒng)。

若要部署,請(qǐng)使用 Azure Functions 核心工具 CLI。

java:

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

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

配置松弛

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

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

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

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

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

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

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

記下您的應(yīng)用簽名密鑰,因?yàn)槟院髮⑹褂盟?/blockquote>

在你進(jìn)入有趣的部分之前

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

FUN(cy)時(shí)間!

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

你應(yīng)該拿回一個(gè)隨機(jī)的 GIF 作為回報(bào)!

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

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

沒(méi)有什么可擔(dān)心的。您所需要的只是重試,一切都會(huì)好起來(lái)的!

清理

當(dāng)我們?cè)谕瓿珊筮@個(gè)測(cè)試之后不要忘記刪除資源組,就是將刪除之前創(chuàng)建的所有資源(功能應(yīng)用、應(yīng)用服務(wù)計(jì)劃等)。 

結(jié)論

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


0 人點(diǎn)贊