Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O Azure Functions executa o código da sua aplicação usando handlers específicos da linguagem. Estes handlers específicos de linguagem permitem que as Funções suportem a maioria das linguagens principais por defeito. No entanto, pode ser necessário executar código noutra linguagem ou pacote.
Os manipuladores personalizados são servidores web de baixa carga que recebem eventos do processo anfitrião do Azure Functions. Pode usar handlers personalizados para implementar em Azure Functions qualquer projeto de código que suporte primitivas HTTP.
Os manipuladores personalizados são mais adequados para situações em que você deseja:
- Implemente uma aplicação de funções numa linguagem que ainda não esteja disponível de fábrica, como Go ou Rust.
- Implemente um aplicativo de função em um tempo de execução que não esteja atualmente apresentado por padrão, como Deno.
- Implemente um servidor construído com os SDKs MCP padrão para o Azure Functions.
Com manipuladores personalizados, você pode usar gatilhos e ligações de entrada e saída por meio de pacotes de extensão.
Introdução aos manipuladores personalizados do Azure Functions com inícios rápidos em Go e Rust.
Descrição geral
O diagrama a seguir mostra a relação entre o host Functions e um servidor Web implementado como um manipulador personalizado.
- Cada evento dispara uma solicitação enviada ao host do Functions. Um evento é qualquer gatilho que o Azure Functions suporta.
- Em seguida, o host Functions emite uma carga útil de solicitação para o servidor Web. A carga útil contém dados de ligação de gatilho e entrada e outros metadados para a função.
- O servidor Web executa a função individual e retorna uma carga útil de resposta para o host Functions.
- O host Functions passa dados da resposta para as ligações de saída da função para processamento.
Um aplicativo do Azure Functions implementado como um manipulador personalizado deve configurar os arquivos de host.json, local.settings.json e function.json de acordo com algumas convenções.
Implementação de servidores MCP auto-hospedados
Os handlers personalizados também permitem alojar servidores MCP que constrói usando SDKs MCP oficiais no Azure Functions. Os handlers personalizados proporcionam uma experiência simples e simplificada para alojar os seus servidores MCP no Azure. Para mais informações, consulte Servidor MCP remoto auto-hospedado no Azure Functions.
Nota
A possibilidade de Azure Functions alojar servidores MCP que cria usando SDKs MCP oficiais está atualmente em pré-visualização.
Estrutura da aplicação
Para implementar um handler personalizado, a sua aplicação precisa dos seguintes aspetos:
- Um arquivo host.json na raiz do seu aplicativo
- Um arquivo local.settings.json na raiz do seu aplicativo
- Um arquivo function.json para cada função (dentro de uma pasta que corresponde ao nome da função)
- Um comando, script ou executável que executa um servidor web
O diagrama a seguir mostra como esses arquivos parecem no sistema de arquivos para uma função chamada "MyQueueFunction" e um executável manipulador personalizado chamado handler.exe.
| /MyQueueFunction
| function.json
|
| host.json
| local.settings.json
| handler.exe
Configuração
Configuras a aplicação através dos ficheiroshost.json e local.settings.json .
host.json
host.json direciona o anfitrião de Funções para onde enviar pedidos, apontando para um servidor web que pode processar eventos HTTP.
Defina um handler personalizado configurando o ficheirohost.json com detalhes sobre como executar o servidor web através da customHandler secção.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
}
}
A customHandler seção aponta para um destino conforme definido pelo defaultExecutablePath. O destino de execução pode ser um comando, executável ou ficheiro onde o servidor web é implementado.
Use a arguments matriz para passar quaisquer argumentos para o executável. Os argumentos suportam a expansão das variáveis de ambiente (definições de aplicação) através da notação %% .
Você também pode alterar o diretório de trabalho usado pelo executável com workingDirectory.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "app/handler.exe",
"arguments": [
"--database-connection-string",
"%DATABASE_CONNECTION_STRING%"
],
"workingDirectory": "app"
}
}
}
Suporte a ligações
Gatilhos padrão, juntamente com ligações de entrada e saída, estão disponíveis fazendo referência a pacotes de extensão em seu arquivo host.json .
local.settings.json
local.settings.json define as configurações do aplicativo usadas ao executar o aplicativo de função localmente. Como pode conter segredos, exclua local.settings.json do controlo de origem. No Azure, use as configurações do aplicativo.
Para manipuladores personalizados, defina FUNCTIONS_WORKER_RUNTIME como Custom em local.settings.json.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "Custom"
}
}
Metadados da função
Quando usas um handler personalizado, o conteúdofunction.json é o mesmo que quando defines uma função em qualquer outro contexto. O único requisito é que deve colocar function.json ficheiros numa pasta nomeada para corresponder ao nome da função.
A function.json a seguir configura uma função que tem um gatilho de fila e uma ligação de saída de fila. Como ele está em uma pasta chamada MyQueueFunction, ele define uma função chamada 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"
}
]
}
Solicitar carga útil
Quando o host Functions recebe uma mensagem de fila, envia um pedido HTTP POST ao handler personalizado com uma carga útil no corpo.
O código seguinte mostra o corpo de uma solicitação de exemplo. A carga útil inclui uma estrutura JSON com dois membros: Data e Metadata.
O Data membro inclui chaves que correspondem aos nomes de entrada e de gatilho, conforme definido na matriz bindings no arquivo function.json .
O Metadata membro inclui metadados gerados a partir da fonte do evento.
{
"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"
}
}
}
Carga útil de resposta
Por convenção, as respostas de função são formatadas como pares chave/valor. As chaves suportadas incluem:
|
|
Tipo de dados | Observações |
|---|---|---|
Outputs |
objecto | Mantém valores de resposta conforme definido pela bindings matriz em function.json.Por exemplo, se uma função estiver configurada com uma ligação de saída de fila chamada "myQueueOutput", então Outputs contém uma chave chamada myQueueOutput, que o handler personalizado define para as mensagens que envia para a fila. |
Logs |
matriz | Mensagens que aparecem nos registos de invocação de Funções. Quando executadas no Azure, as mensagens aparecem no Application Insights. |
ReturnValue |
cadeia (de caracteres) | Usado para fornecer uma resposta quando uma saída é configurada como $return no arquivo function.json. |
Esta tabela mostra um exemplo de carga útil de resposta.
{
"Outputs": {
"res": {
"body": "Message enqueued"
},
"myQueueOutput": [
"queue message 1",
"queue message 2"
]
},
"Logs": [
"Log message 1",
"Log message 2"
],
"ReturnValue": "{\"hello\":\"world\"}"
}
Exemplos
Pode implementar handlers personalizados em qualquer linguagem que suporte receção de eventos HTTP. Os exemplos seguintes mostram como implementar um handler personalizado usando a linguagem de programação Go.
Função com ligações
Este exemplo mostra uma função nomeada order que aceita um POST pedido com uma carga útil representando uma encomenda de produto. Quando envia um pedido à função, esta cria uma mensagem na Fila de Armazenamento e devolve uma resposta HTTP.
Implementação
Em uma pasta chamada ordem, o arquivo function.json configura a função acionada por HTTP.
ordem/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"
}
]
}
Essa função é definida como uma função acionada por HTTP que retorna uma resposta HTTP e gera uma mensagem de armazenamento de fila.
Na raiz do aplicativo, o arquivo host.json é configurado para executar um arquivo executável chamado handler.exe (handler no Linux ou macOS).
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
}
}
Esta é a solicitação HTTP enviada para o tempo de execução do Functions.
POST http://127.0.0.1:7071/api/order HTTP/1.1
Content-Type: application/json
{
"id": 1005,
"quantity": 2,
"color": "black"
}
O runtime Functions envia o seguinte pedido HTTP ao handler personalizado:
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": {
}
}
Nota
Algumas partes da carga útil foram removidas por uma questão de brevidade.
handler.exe é o programa de manipulador personalizado Go compilado que executa um servidor Web e responde a solicitações de invocação de função do host 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))
}
Neste exemplo, o handler personalizado executa um servidor web para tratar eventos HTTP e escuta pedidos através do FUNCTIONS_CUSTOMHANDLER_PORT.
Embora o host de Funções receba o pedido HTTP original em /api/order, ele invoca o handler personalizado usando o nome da função (o nome da sua pasta). Neste exemplo, a função é definida no caminho de /order. O host envia ao manipulador personalizado uma solicitação HTTP no caminho do /order.
Quando envia POST pedidos para esta função, os dados do gatilho e os metadados da função estão disponíveis através do corpo do pedido HTTP. Pode aceder ao corpo original do pedido HTTP no payload do Data.req.Body.
A resposta da função é formatada em pares chave/valor onde o Outputs membro detém um valor JSON onde as chaves correspondem às saídas conforme definido no arquivo function.json .
Este é um exemplo de carga útil que esse manipulador retorna ao host Functions.
{
"Outputs": {
"message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
"res": {
"body": "Order enqueued"
}
},
"Logs": null,
"ReturnValue": null
}
Ao definir a message saída igual aos dados de ordem que vieram da solicitação, a função envia esses dados de ordem para a fila configurada. O host Functions também retorna a resposta HTTP configurada no res chamador.
Função somente HTTP
Para funções ativadas por HTTP sem ligações ou saídas adicionais, pode querer que o seu handler trabalhe diretamente com o pedido e a resposta HTTP em vez das cargas úteis do pedido request e da resposta response personalizada do handler. Pode configurar este comportamento em host.json usando a enableProxyingHttpRequest definição, que suporta streaming de respostas.
Importante
O principal objetivo da funcionalidade de handlers personalizados é permitir linguagens e runtimes que atualmente não têm suporte de primeira classe no Azure Functions. Embora possas conseguir correr aplicações web usando handlers personalizados, o Azure Functions não é um proxy reverso padrão. Alguns componentes do pedido HTTP, como certos cabeçalhos e rotas, podem estar restritos. A sua aplicação também pode sofrer um arranque frio excessivo.
Para resolver essas circunstâncias, considere executar seus aplicativos Web no Serviço de Aplicativo do Azure.
O exemplo a seguir demonstra como configurar uma função acionada por HTTP sem ligações ou saídas adicionais. O cenário implementado neste exemplo apresenta uma função chamada hello que aceita um GET ou POST .
Implementação
Em uma pasta chamada hello, o arquivo function.json configura a função acionada por HTTP.
Olá/function.json
{
"bindings": [
{
"type": "httpTrigger",
"authLevel": "function",
"direction": "in",
"name": "req",
"methods": ["get", "post"]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
A função está configurada para aceitar tanto GET como POST solicitações, e o valor do resultado é fornecido através de um argumento chamado res.
Na raiz do aplicativo, o arquivo host.json está configurado para ser executado handler.exe e enableProxyingHttpRequest definido como true.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
},
"enableProxyingHttpRequest": true
}
}
O seguinte é um pedido POST ao anfitrião das Functions. O anfitrião Functions envia então o pedido para o handler personalizado.
POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json
{
"message": "Hello World!"
}
O ficheiro handler.go implementa um servidor web e uma função 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))
}
Neste exemplo, o handler personalizado cria um servidor web para tratar eventos HTTP e escuta pedidos através do FUNCTIONS_CUSTOMHANDLER_PORT.
GET As solicitações são tratadas retornando uma cadeia de caracteres e POST as solicitações têm acesso ao corpo da solicitação.
A rota para a função de ordem aqui é /api/hello, igual à solicitação original.
Nota
FUNCTIONS_CUSTOMHANDLER_PORT não é a porta pública usada para chamar a função. O anfitrião Functions usa esta porta para chamar o handler personalizado.
Implementação
Podes implementar um handler personalizado em todas as opções de alojamento do Azure Functions. Se o seu handler requer dependências do sistema operativo ou da plataforma (como um runtime de linguagem), poderá precisar de usar um contentor personalizado.
Quando criares uma aplicação de funções no Azure para handlers personalizados, seleciona .NET Core como stack.
Para implementar uma aplicação handler personalizada usando as Ferramentas Core do Azure Functions, execute o seguinte comando.
func azure functionapp publish $functionAppName
Nota
Verifique se todos os arquivos necessários para executar seu manipulador personalizado estão na pasta e incluídos na implantação. Se o manipulador personalizado for um executável binário ou tiver dependências específicas da plataforma, verifique se esses arquivos correspondem à plataforma de implantação de destino.
Restrições
- O servidor Web do manipulador personalizado precisa ser iniciado dentro de 60 segundos.
Exemplos
Para exemplos de como implementar funções em várias linguagens diferentes, consulte o repositório GitHub de exemplos de handler personalizados.
Resolução de problemas e suporte
Registo de rastreio
Se o seu processo de handler personalizado falhar ao iniciar ou se tiver problemas de comunicação com o anfitrião de Funções, aumente o nível de log da aplicação de funções para Trace ver mais mensagens de diagnóstico do anfitrião.
Para alterar o nível de log padrão do aplicativo de função, defina a logLevellogging configuração na seção de host.json.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
O host de Funções gera mensagens de registo extra, incluindo informações relacionadas com o processo do handler personalizado. Use os logs para investigar problemas ao iniciar o processo do manipulador personalizado ou invocar funções no manipulador personalizado.
Localmente, os logs são impressos no console.
No Azure, consulte rastreamentos do Application Insights para exibir as mensagens de log. Se seu aplicativo produzir um grande volume de logs, apenas um subconjunto de mensagens de log será enviado para o Application Insights. Desative a amostragem para garantir que todas as mensagens sejam registradas.
Testar manipulador personalizado isoladamente
As aplicações handler personalizadas são processos de servidor web, por isso pode ser útil iniciá-las sozinhas e testar invocações de funções enviando pedidos HTTP simulados. Para enviar solicitações HTTP com cargas úteis, certifique-se de escolher uma ferramenta que mantenha seus dados seguros. Para obter mais informações, consulte Ferramentas de teste HTTP.
Você também pode usar essa estratégia em seus pipelines de CI/CD para executar testes automatizados em seu manipulador personalizado.
Ambiente de execução
Os manipuladores personalizados são executados no mesmo ambiente que um aplicativo típico do Azure Functions. Teste seu manipulador para garantir que o ambiente contenha todas as dependências necessárias para ser executado. Para aplicações que requerem dependências adicionais, pode ser necessário executá-las usando uma imagem container personalizada alojada no plano Premium do Azure Functions.
Obter suporte
Se precisar de ajuda em um aplicativo de função com manipuladores personalizados, você pode enviar uma solicitação por meio de canais de suporte regulares. No entanto, devido à grande variedade de linguagens possíveis usadas para construir aplicações de handlers personalizados, o suporte não é ilimitado.
O suporte estará disponível se o host Functions tiver problemas para iniciar ou se comunicar com o processo do manipulador personalizado. Para problemas específicos do funcionamento interno do seu processo de handler personalizado, como problemas com a linguagem ou framework escolhido, a nossa Equipa de Suporte não pode prestar assistência neste contexto.
Próximos passos
Comece a criar um aplicativo do Azure Functions em Go ou Rust com o início rápido de manipuladores personalizados.