共用方式為


Azure Functions 自訂處理常式

Azure Functions 會透過語言特定的處理常式來執行您的應用程式程式碼。 這些語言特定的處理常式使得 Functions 預設能支援大多數重要語言。 不過,你可能需要用另一種語言或套件執行程式碼。

自訂處理程式是輕量級的網頁伺服器,會接收來自 Azure Functions 主控程序的事件。 你可以使用自訂處理器將任何支援 HTTP 原語的程式碼專案部署到 Azure Functions。

自訂處理常式最適合以下情況:

  • 在目前未現成提供的語言 (例如 Go 或 Rust) 中實作函式應用程式。
  • 在目前未預設提供的執行階段 (例如 Deno) 中實作函式應用程式。
  • 將用標準 MCP SDK 建置的伺服器部署到 Azure Functions。

透過自訂處理常式,您可以透過延伸模組套件組合使用觸發程序和輸入和輸出繫結

使用 Go 和 Rust 中的快速入門,開始使用 Azure Functions 自訂處理常式。

概觀

下圖顯示 Functions 主機與實作為自訂處理常式的網頁伺服器之間的關聯性。

Azure Functions 自訂處理常式概觀

  1. 每個事件都會觸發傳送至 Functions 主機的要求。 事件是 Azure Functions 支援的任何觸發事件。
  2. 然後 Functions 主機會向網頁伺服器發出要求承載。 承載會保存函式的觸發程序和輸入繫結資料與其他中繼資料。
  3. 網頁伺服器會執行個別函式,並將回應承載傳回至 Functions 主機。
  4. Functions 主機會將來自回應的資料傳遞至函式的輸出繫結進行處理。

實作為自訂處理常式的 Azure Functions 應用程式必須根據一些慣例來設定 host.jsonlocal.settings.jsonfunction.json 檔案。

部署自架 MCP 伺服器

自訂處理常式還讓您可以透過使用 Azure Functions 中的官方 MCP SDK 來託管您建置的 MCP 伺服器。 自訂處理程序提供簡單且流暢的在 Azure 上託管 MCP 伺服器的體驗。 欲了解更多資訊,請參閱 Azure Functions 上的自架遠端 MCP 伺服器

附註

Azure Functions 能夠託管你使用官方 MCP SDK 建立的 MCP 伺服器的功能目前處於預覽階段。

應用程式結構

若要執行自訂處理常式,您的應用程式需要以下幾個面向:

  • 應用程式根目錄中有 host.json 檔案
  • 應用程式根目錄中有 local.settings.json 檔案
  • 每個函式的 function.json 檔案 (在符合函式名稱的資料夾內)
  • 一個執行網頁伺服器的指令、腳本或執行檔

針對名為 "MyQueueFunction" 的函式以及名為 handler.exe 的自訂處理常式可執行檔,下圖顯示這些檔案在檔案系統看起來的樣子。

| /MyQueueFunction
|   function.json
|
| host.json
| local.settings.json
| handler.exe

組態

你透過 host.jsonlocal.settings.json 檔案來設定應用程式。

host.json

host.json 會指向能處理 HTTP 事件的網頁伺服器,指示函數主機將請求傳送到哪裡。

藉由設定 host.json 檔案來定義自訂處理常式,其中包含如何透過 customHandler 區段執行網頁伺服器的詳細資料。

{
  "version": "2.0",
  "customHandler": {
    "description": {
      "defaultExecutablePath": "handler.exe"
    }
  }
}

customHandler 區段會指向由 defaultExecutablePath 所定義的目標。 執行目標可以是指令、可執行檔或實作網頁伺服器的檔案。

使用 arguments 陣列將任何引數傳遞至該可執行檔。 參數支援透過符號 %% 來擴充環境變數(應用程式設定)。

您也可以使用 workingDirectory 來變更可執行檔所使用的工作目錄。

{
  "version": "2.0",
  "customHandler": {
    "description": {
      "defaultExecutablePath": "app/handler.exe",
      "arguments": [
        "--database-connection-string",
        "%DATABASE_CONNECTION_STRING%"
      ],
      "workingDirectory": "app"
    }
  }
}
繫結支援

參考 host.json 檔案中的延伸模組套件組合,即可使用標準觸發程序和輸出繫結。

local.settings.json

local.settings.json 會定義在本機執行函式應用程式時所使用的應用程式設定。 因為可能包含秘密,請將 local.settings.json 排除在原始碼控制之外。 在 Azure 中,請改用應用程式設定。

針對自訂處理常式,請在 FUNCTIONS_WORKER_RUNTIME 中將 Custom 設定為

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "Custom"
  }
}

函式中繼資料

使用自訂處理器時,function.json 的內容與在其他情境中定義函數時相同。 唯一的要求是你必須將 function.json 檔案放入與函式名稱相符的資料夾中。

下列 function.json 會設定具有佇列觸發程序和佇列輸出繫結的函式。 因為它位於名為 MyQueueFunction 的資料夾,其會定義名為 MyQueueFunction 的函式。

MyQueueFunction/function.json

{
  "bindings": [
    {
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "messages-incoming",
      "connection": "AzureWebJobsStorage"
    },
    {
      "name": "$return",
      "type": "queue",
      "direction": "out",
      "queueName": "messages-outgoing",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

要求承載

當 Functions 主機收到佇列訊息時,它會將 HTTP post 要求傳送至內文中具有承載的自訂處理常式。

以下程式碼顯示一個範例請求負載。 承載包含的 JSON 結構具有兩個成員:DataMetadata

Data 成員包含符合 function.json 檔案的繫結陣列中定義的輸入和觸發程序名稱的金鑰。

Metadata 成員包含從事件來源產生的中繼資料

{
  "Data": {
    "myQueueItem": "{ message: \"Message sent\" }"
  },
  "Metadata": {
    "DequeueCount": 1,
    "ExpirationTime": "2019-10-16T17:58:31+00:00",
    "Id": "800ae4b3-bdd2-4c08-badd-f08e5a34b865",
    "InsertionTime": "2019-10-09T17:58:31+00:00",
    "NextVisibleTime": "2019-10-09T18:08:32+00:00",
    "PopReceipt": "AgAAAAMAAAAAAAAAAgtnj8x+1QE=",
    "sys": {
      "MethodName": "QueueTrigger",
      "UtcNow": "2019-10-09T17:58:32.2205399Z",
      "RandGuid": "24ad4c06-24ad-4e5b-8294-3da9714877e9"
    }
  }
}

回應承載

依慣例,函式回應會格式化為金鑰/值組。 支援的金鑰包括:

承載金鑰 資料類型 備註
Outputs 物件 保留 bindings 陣列所定義的回應值。

例如,如果一個函式設定了一個名為「myQueueOutput」的佇列輸出綁定,則 Outputs 會包含一個名為 myQueueOutput的金鑰,自訂處理器會將它設定為它發送給佇列的訊息。
Logs 陣列 出現在函式調用日誌中的訊息。

在 Azure 中執行時,訊息會出現在 Application Insights 中。
ReturnValue 字串 用於在 $return 檔案中將輸出設定為 時提供回應。

下表展示了回應有效載荷的範例。

{
  "Outputs": {
    "res": {
      "body": "Message enqueued"
    },
    "myQueueOutput": [
      "queue message 1",
      "queue message 2"
    ]
  },
  "Logs": [
    "Log message 1",
    "Log message 2"
  ],
  "ReturnValue": "{\"hello\":\"world\"}"
}

範例

您可以在支援接收 HTTP 事件的任何語言中實作自訂處理常式。 下列範例示範如何使用 Go 程式設計語言來實作自訂處理常式。

具有繫結的函式

此範例展示了一個名為 order 的函式,該函式接受一個代表產品訂單的 POST 資料負載請求。 當你向函式發布訂單時,它會建立佇列儲存訊息並回傳 HTTP 回應。

實作

在名為 order 的資料夾中,function.json 檔案會設定 HTTP 觸發的函式。

order/function.json

{
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "queue",
      "name": "message",
      "direction": "out",
      "queueName": "orders",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

此函式定義為 HTTP 觸發的函式,可傳回 HTTP 回應並輸出佇列儲存體訊息。

在應用程式的根目錄中,host.json 檔案會設定為執行名為 handler.exe 的可執行檔 (在 Linux 或 macOS 中為 handler)。

{
  "version": "2.0",
  "customHandler": {
    "description": {
      "defaultExecutablePath": "handler.exe"
    }
  },
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle",
    "version": "[4.*, 5.0.0)"
  }
}

這是傳送至 Functions 執行階段的 HTTP 要求。

POST http://127.0.0.1:7071/api/order HTTP/1.1
Content-Type: application/json

{
  "id": 1005,
  "quantity": 2,
  "color": "black"
}

Functions 執行時會向自訂處理器發送以下 HTTP 請求:

POST http://127.0.0.1:<FUNCTIONS_CUSTOMHANDLER_PORT>/order HTTP/1.1
Content-Type: application/json

{
  "Data": {
    "req": {
      "Url": "http://localhost:7071/api/order",
      "Method": "POST",
      "Query": "{}",
      "Headers": {
        "Content-Type": [
          "application/json"
        ]
      },
      "Params": {},
      "Body": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}"
    }
  },
  "Metadata": {
  }
}

附註

為了簡潔起見,已移除承載的某些部分。

handler.exe 是編譯的 Go 自訂處理常式程式,其會執行網頁伺服器,並回應來自 Functions 主機的函式叫用要求。

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"os"
)

type InvokeRequest struct {
	Data     map[string]json.RawMessage
	Metadata map[string]interface{}
}

type InvokeResponse struct {
	Outputs     map[string]interface{}
	Logs        []string
	ReturnValue interface{}
}

func orderHandler(w http.ResponseWriter, r *http.Request) {
	var invokeRequest InvokeRequest

	d := json.NewDecoder(r.Body)
	d.Decode(&invokeRequest)

	var reqData map[string]interface{}
	json.Unmarshal(invokeRequest.Data["req"], &reqData)

	outputs := make(map[string]interface{})
	outputs["message"] = reqData["Body"]

	resData := make(map[string]interface{})
	resData["body"] = "Order enqueued"
	outputs["res"] = resData
	invokeResponse := InvokeResponse{outputs, nil, nil}

	responseJson, _ := json.Marshal(invokeResponse)

	w.Header().Set("Content-Type", "application/json")
	w.Write(responseJson)
}

func main() {
	customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
	if !exists {
		customHandlerPort = "8080"
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/order", orderHandler)
	fmt.Println("Go server Listening on: ", customHandlerPort)
	log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}

在此範例中,自訂處理常式會執行網頁伺服器來處理 HTTP 事件,並透過 FUNCTIONS_CUSTOMHANDLER_PORT 接聽要求。

即使函式主機在 接收原始 /api/orderHTTP 請求,仍會透過函式名稱(資料夾名稱)呼叫自訂處理程序。 在此範例中,函式定義於路徑 /order。 主機會在 /order 的路徑傳送 HTTP 要求給自訂處理常式。

當你向這個函式發送 POST 請求時,觸發資料和函式元資料會透過 HTTP 請求體取得。 你可以存取 payload Data.req.Body的原始 HTTP 請求主體。

函式的回應會格式化為金鑰/值組,其中的 Outputs 成員會保存 JSON 值,而金鑰會符合 function.json 檔案中所定義的輸出。

這是此處理常式傳回至 Functions 主機的範例承載。

{
  "Outputs": {
    "message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
    "res": {
      "body": "Order enqueued"
    }
  },
  "Logs": null,
  "ReturnValue": null
}

藉由將 message 輸出設定為等於來自要求的訂單資料,函式會將訂單資料輸出至已設定的佇列。 Functions 主機也會向呼叫端傳回在 res 中設定的 HTTP 回應。

僅限 HTTP 的函式

對於沒有額外綁定或輸出的 HTTP 觸發函式來說,你可能希望讓處理函式直接處理 HTTP 請求和回應,而不是使用自訂處理函式的 請求回應 負載。 你可以在 host.jsonenableProxyingHttpRequest 使用支援回應串流的設定來設定此行為。

重要事項

自訂處理常式功能的主要用途是啟用目前在 Azure Functions 上沒有第一級支援的語言和執行階段。 雖然你可能可以用自訂的處理常式來執行網頁應用程式,但 Azure Functions 並不是標準的反向代理。 HTTP 請求的某些元件,例如某些標頭和路由,可能會受到限制。 你的應用也可能遇到過度 冷啟動的情況。

若要解決這些情況,請考量在 Azure App Service 上執行 Web 應用程式。

下列範例示範如何設定不含其他繫結或輸出的 HTTP 觸發函式。 在此範例中實作的案例包含名為 hello 的函式,其的接受 GETPOST

實作

在名為 hello 的資料夾中,function.json 檔案會設定 HTTP 觸發的函式。

hello/function.json

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

函式設定為同時接受 GETPOST 請求,結果值透過名為 res的參數提供。

在應用程式的根目錄中,host.json 檔案會設定為執行 handler.exe,且 enableProxyingHttpRequest 會設定為 true

{
  "version": "2.0",
  "customHandler": {
    "description": {
      "defaultExecutablePath": "handler.exe"
    },
    "enableProxyingHttpRequest": true
  }
}

以下是對函式主機的 POST 請求。 函數主機接著將請求傳送給自訂處理器。

POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json

{
  "message": "Hello World!"
}

handler.go 檔案實作了網頁伺服器和 HTTP 函式。

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/json")
	if r.Method == "GET" {
		w.Write([]byte("hello world"))
	} else {
		body, _ := ioutil.ReadAll(r.Body)
		w.Write(body)
	}
}

func main() {
	customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
	if !exists {
		customHandlerPort = "8080"
	}
	mux := http.NewServeMux()
	mux.HandleFunc("/api/hello", helloHandler)
	fmt.Println("Go server Listening on: ", customHandlerPort)
	log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}

在此範例中,自訂處理常式會建立網頁伺服器來處理 HTTP 事件,並透過 FUNCTIONS_CUSTOMHANDLER_PORT 接聽要求。

GET 要求會藉由傳回字串來處理,而 POST 要求可以存取要求本文。

這裡的訂單函式路由為 /api/hello,與原始要求相同。

附註

FUNCTIONS_CUSTOMHANDLER_PORT 並不是用來呼叫函式的公開埠。 函式主機會使用此埠來呼叫自訂處理器。

正在部署

您可以為每個 Azure Functions 託管選項部署自訂處理常式。 如果您的處理常式需要作業系統或平台相依性(例如語言執行環境),您可能需要使用 自訂容器

當您在 Azure 中為自訂處理常式建立函式應用程式時,選取 .NET Core 作為堆疊。

要使用 Azure Functions Core Tools 部署自訂處理程式應用程式,請執行以下指令。

func azure functionapp publish $functionAppName

附註

確保執行您的自訂處理常式所需的所有檔案都位於資料夾中,並包含在部署中。 如果您的自訂處理常式是二進位可執行檔,或具有平台特定的相依性,請確保這些檔案符合目標部署平台。

限制

  • 自訂處理常式網頁伺服器必須在 60 秒內啟動。

範例

關於如何用多種不同語言實作函式的範例,請參考 GitHub 倉庫的自訂處理程式範例

疑難排解和支援

追蹤記錄

如果您的自訂處理程序無法啟動,或與 Functions 主機溝通有問題,請提高函數應用程式的日誌等級至 Trace,以便查看來自主機的更多診斷訊息。

若要變更函式應用程式的預設記錄層級,請在 logLevellogging 區段中設定 設定。

{
  "version": "2.0",
  "customHandler": {
    "description": {
      "defaultExecutablePath": "handler.exe"
    }
  },
  "logging": {
    "logLevel": {
      "default": "Trace"
    }
  }
}

函式主機會輸出額外的日誌訊息,包括與自訂處理常式程序相關的資訊。 使用記錄來調查啟動自訂處理常式程序或在自訂處理常式中叫用函式的問題。

在本機,記錄會列印到主控台。

在 Azure 中,查詢 Application Insights 追蹤以檢視記錄訊息。 如果您的應用程式會產生大量記錄,則只會將記錄訊息的子集傳送至 Application Insights。 停用取樣以確保會記錄所有訊息。

隔離測試自訂處理常式

自訂處理程式是網頁伺服器程序,因此單獨啟動它們並透過發送模擬 HTTP 請求來測試函式調用可能會有幫助。 若要傳送具有承載的 HTTP 要求,請務必選擇可保護您的資料的工具。 如需詳細資訊,請參閱 HTTP 測試工具

您也可以在 CI/CD 管線中使用此策略,以在自訂處理常式上執行自動化測試。

執行環境

自訂處理常式會在與一般 Azure Functions 應用程式相同的環境中執行。 測試您的處理常式,以確保環境包含它執行所需的所有相依性。 對於需要額外相依的應用程式,你可能需要使用在 Azure Functions Premium 方案上託管的自訂容器映像來執行。

取得支援

如果您需要使用自訂處理常式的函式應用程式的協助,您可以透過一般支援管道提交要求。 不過,由於用來建置自訂處理常式應用程式的廣泛語言,支援並非無限制提供。

如果 Functions 主機發生啟動或與自訂處理常式通訊的問題,則會提供支援。 對於自訂處理流程內部運作的問題,例如所選語言或框架的問題,我們的支援團隊無法在此情境下提供協助。

後續步驟

使用自訂處理常式快速入門,開始在 Go 或 Rust 中建置 Azure Functions 應用程式。