Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
O Azure Functions executa o código do aplicativo usando manipuladores específicos de linguagem. Esses manipuladores específicos do idioma permitem que o Functions dê suporte à maioria dos idiomas principais por padrão. No entanto, talvez seja necessário executar código em outro idioma ou pacote.
Os manipuladores personalizados são servidores Web leves que recebem eventos do processo de host do Azure Functions. Você pode usar manipuladores personalizados para implantar no Azure Functions qualquer projeto de código que dê suporte a primitivos HTTP.
Os manipuladores personalizados são mais adequados para situações em que você deseja:
- Implemente um aplicativo de funções em um idioma que atualmente não é oferecido pronto para uso, como Go ou Rust.
- Implementar um aplicativo de funções em um runtime que não tenha suporte atualmente, como Deno.
- Implante um servidor criado com os SDKs do MCP padrão no Azure Functions.
Com manipuladores personalizados, você pode usar gatilhos e associações de entrada e saída por meio de pacotes de extensão.
Introdução a manipuladores personalizados do Azure Functions com os guias de início rápido em Go e Rust.
Visão geral
O diagrama a seguir mostra a relação entre o host do 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 compatível com o Azure Functions.
- O host do Functions emite, então, um payload de solicitação para o servidor Web. O payload contém dados de associação de entrada e de gatilho e outros metadados para a função.
- O servidor Web executa a função individual e retorna um payload de resposta para o host do Functions.
- O host do Functions passa dados da resposta para as associações de saída da função para processamento.
Um aplicativo Azure Functions implementado como um manipulador personalizado deve configurar arquivos host.json, local.settings.jsone function.json de acordo com algumas convenções.
Implantar servidores MCP auto-hospedados
Os manipuladores personalizados também permitem hospedar servidores MCP que você cria usando SDKs oficiais do MCP no Azure Functions. Os manipuladores personalizados fornecem uma experiência simples e simplificada para hospedar seus servidores MCP no Azure. Para obter mais informações, consulte o servidor MCP remoto auto-hospedado no Azure Functions.
Observação
A capacidade de Azure Functions hospedar servidores MCP que você cria usando SDKs oficiais do MCP está atualmente em prévia.
Estrutura de aplicativo
Para implementar um manipulador personalizado, seu aplicativo precisa dos seguintes aspectos:
- 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 examinam o sistema de arquivos em busca de uma função chamada "MyQueueFunction" e um executável do manipulador personalizado chamado handler.exe.
| /MyQueueFunction
| function.json
|
| host.json
| local.settings.json
| handler.exe
Configuração
Configure o aplicativo por meio dos arquivos host.json e local.settings.json .
host.json
host.json direciona o host do Functions para onde enviar solicitações apontando para um servidor Web que pode processar eventos HTTP.
Defina um manipulador personalizado configurando o arquivo host.json com detalhes sobre como executar o servidor Web por meio da customHandler seção.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
}
}
A seção customHandler aponta para um destino, conforme definido por defaultExecutablePath. O destino de execução pode ser um comando, executável ou um arquivo em que o servidor Web é implementado.
Use a matriz arguments para passar quaisquer argumentos para o executável. Os argumentos dão suporte à expansão de variáveis de ambiente (configurações de aplicativo) usando %% 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 associações
Os gatilhos padrão, juntamente com as associações de entrada e saída, estão disponíveis por meio da referência de pacotes de extensão em seu arquivo host.json.
local.settings.json
O local.settings.json define as configurações do aplicativo usadas ao executar o aplicativo de funções localmente. Como pode conter segredos, exclua local.settings.json do controle do código-fonte. No Azure, use as configurações de aplicativo em vez disso.
Para manipuladores personalizados, defina FUNCTIONS_WORKER_RUNTIME como Custom no local.settings.json.
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "Custom"
}
}
Metadados de função
Quando você usa um manipulador personalizado, o function.json conteúdo é o mesmo que quando você define uma função em qualquer outro contexto. O único requisito é que você deve colocar function.json arquivos em uma pasta nomeada para corresponder ao nome da função.
O function.json a seguir configura uma função que tem um gatilho de fila e uma associação de saída de fila. Por estar 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"
}
]
}
Payload da solicitação
Quando o host do Functions recebe uma mensagem de fila, ele envia uma solicitação HTTP POST para o manipulador personalizado com uma carga útil no corpo da solicitação.
O código a seguir mostra um payload de solicitação de exemplo. O payload inclui uma estrutura JSON com dois membros: Data e Metadata.
O membro Data inclui chaves que correspondem aos nomes de entrada e de gatilho, conforme definido na matriz de associações no arquivo function.json.
O membro Metadata inclui metadados gerados da origem 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"
}
}
}
Payload de resposta
Por convenção, as respostas de função são formatadas como pares chave/valor. As chaves com suporte incluem:
|
|
Tipo de dados | Comentários |
|---|---|---|
Outputs |
objeto | Mantém valores de resposta conforme definido pela matriz bindings no function.json.Por exemplo, se uma função estiver configurada com uma associação de saída de fila chamada "myQueueOutput", conterá Outputs uma chave nomeada myQueueOutput, que o manipulador personalizado define para as mensagens que ela envia para a fila. |
Logs |
matriz | Mensagens que aparecem nos logs de invocação do Functions. Quando em execução no Azure, as mensagens aparecem no Application Insights. |
ReturnValue |
cadeia | 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
Você pode implementar manipuladores personalizados em qualquer idioma que dê suporte ao recebimento de eventos HTTP. Os exemplos a seguir mostram como implementar um manipulador personalizado usando a linguagem de programação Go.
Função com associações
Este exemplo mostra uma função nomeada order que aceita uma solicitação POST com uma carga que representa um pedido de produto. Quando você posta uma ordem na função, ela cria uma mensagem de Armazenamento de Filas e retorna uma resposta HTTP.
Implementação
Em uma pasta chamada Pedido, o arquivo function.json configura a função disparada por 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"
}
]
}
Essa função é definida como uma função disparada 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)"
}
}
Essa é a solicitação HTTP enviada ao runtime 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 do Functions envia a seguinte solicitação HTTP para o manipulador 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": {
}
}
Observação
Algumas partes do payload foram removidas para fins de brevidade.
O handler.exe é o programa do manipulador personalizado Go compilado que executa um servidor Web e responde a solicitações de invocação de função do host do 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 manipulador personalizado executa um servidor Web para lidar com eventos HTTP e escuta solicitações por meio do FUNCTIONS_CUSTOMHANDLER_PORT.
Embora o host do Functions receba a solicitação HTTP original em /api/order, ele invoca o manipulador personalizado usando o nome da função (seu nome de pasta). Nesse exemplo, a função é definida no caminho de /order. O host envia ao manipulador personalizado uma solicitação HTTP no caminho de /order.
Quando você envia POST solicitações para essa função, os dados de gatilho e os metadados de função estão disponíveis por meio do corpo da solicitação HTTP. Você pode acessar o corpo da solicitação HTTP original na carga útil do Data.req.Body.
A resposta da função é formatada em pares chave/valor em que o membro Outputs mantém um valor JSON em que as chaves correspondem às saídas, conforme definido no arquivo function.json.
Esse é um exemplo de payload que esse manipulador retorna para o host do Functions.
{
"Outputs": {
"message": "{\"id\":1005,\"quantity\":2,\"color\":\"black\"}",
"res": {
"body": "Order enqueued"
}
},
"Logs": null,
"ReturnValue": null
}
Ao definir a saída message igual aos dados de pedidos que vieram da solicitação, a função gera esses dados de pedidos para a fila configurada. O host do Functions também retorna a resposta HTTP configurada em res para o chamador.
Função somente HTTP
Para funções disparadas por HTTP sem associações ou saídas adicionais, talvez você queira que seu manipulador trabalhe diretamente com a solicitação HTTP e a resposta em vez dos conteúdos de solicitação e resposta do manipulador personalizado. Você pode configurar esse comportamento em host.json usando a enableProxyingHttpRequest configuração, que dá suporte ao streaming de resposta.
Importante
A principal finalidade do recurso de manipuladores personalizados é habilitar idiomas e runtimes que atualmente não têm suporte de primeira classe no Azure Functions. Embora você possa executar aplicativos Web usando manipuladores personalizados, o Azure Functions não é um proxy reverso padrão. Alguns componentes da solicitação HTTP, como determinados cabeçalhos e rotas, podem ser restritos. Seu aplicativo também pode ter um início frio excessivo.
Para tratar dessas circunstâncias, cogite executar seus aplicativos Web no Serviço de Aplicativo do Azure.
O exemplo a seguir demonstra como configurar uma função disparada por HTTP sem associações ou saídas adicionais. O cenário implementado nesse 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 disparada por HTTP.
hello/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 solicitações de GET e POST, e o valor do resultado é fornecido através de um argumento chamado res.
Na raiz do aplicativo, o arquivo host.json é configurado para executar handler.exe, e enableProxyingHttpRequest é definida como true.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
},
"enableProxyingHttpRequest": true
}
}
Veja a seguir uma solicitação POST para o host do Functions. O host do Functions envia a solicitação para o manipulador personalizado.
POST http://127.0.0.1:7071/api/hello HTTP/1.1
Content-Type: application/json
{
"message": "Hello World!"
}
O arquivo 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 manipulador personalizado cria um servidor Web para lidar com eventos HTTP e escuta solicitações por meio do FUNCTIONS_CUSTOMHANDLER_PORT.
As solicitações GET são tratadas ao retornar uma cadeia de caracteres, e as solicitações POST têm acesso ao corpo da solicitação.
A rota para a função de pedido aqui é /api/hello, igual à solicitação original.
Observação
A FUNCTIONS_CUSTOMHANDLER_PORT não é a porta voltada para o público usada para chamar a função. O host do Functions usa essa porta para chamar o manipulador personalizado.
Implantando
Você pode implantar um manipulador personalizado em todas as opções de hospedagem do Azure Functions. Se o manipulador exigir dependências do sistema operacional ou da plataforma (como um runtime de idioma), talvez seja necessário usar um contêiner personalizado.
Ao criar um aplicativo de funções no Azure para manipuladores personalizados, selecione .NET Core como o framework.
Para implantar um aplicativo de manipulador personalizado usando as Ferramentas Principais do Azure Functions, execute o comando a seguir.
func azure functionapp publish $functionAppName
Observação
Verifique se todos os arquivos necessários para executar o manipulador personalizado estão na pasta e incluídos na implantação. Se seu 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 começar dentro de 60 segundos.
Exemplos
Para obter exemplos de como implementar funções em uma variedade de idiomas diferentes, consulte o repositório GitHub de exemplos de manipulador personalizado.
Solução de problemas e suporte
Log de rastreamento
Se o processo de manipulador personalizado não for iniciado ou se ele tiver problemas para se comunicar com o host do Functions, aumente o nível de log do aplicativo de funções para Trace para ver mais mensagens de diagnóstico do host.
Para alterar o nível de log padrão do aplicativo de funções, defina a configuração logLevel na seção logging do host.json.
{
"version": "2.0",
"customHandler": {
"description": {
"defaultExecutablePath": "handler.exe"
}
},
"logging": {
"logLevel": {
"default": "Trace"
}
}
}
O host do Functions gera mensagens de log extras, incluindo informações relacionadas ao processo de manipulador personalizado. Use os logs para investigar problemas que iniciam o processo do manipulador personalizado ou que invocam funções em seu manipulador personalizado.
Localmente, os logs são impressos no console.
No Azure, confira os rastreamentos do Application Insights para exibir as mensagens de log. Caso seu aplicativo produza um alto volume de logs, apenas um subconjunto de mensagens de log será enviado para o Application Insights. Desabilite a amostragem para garantir que todas as mensagens sejam registradas em log.
Testar o manipulador personalizado em isolamento
Aplicativos de manipulador personalizado são processos de servidor Web, portanto, pode ser útil iniciá-los por conta própria e testar invocações de função enviando solicitações HTTP simuladas. Para enviar solicitações HTTP com cargas, certifique-se de escolher uma ferramenta que mantenha seus dados seguros. Para obter mais informações, confira 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 de um aplicativo Azure Functions típico. Teste seu manipulador para garantir que o ambiente contenha todas as dependências necessárias para ser executado. Para aplicativos que exigem dependências adicionais, talvez seja necessário executá-las usando uma imagem de contêiner personalizada hospedada no plano Premium do Azure Functions.
Obtenha suporte
Caso precise de ajuda em um aplicativo de funções com manipuladores personalizados, você poderá enviar uma solicitação por meio de canais de suporte regular. No entanto, devido à ampla variedade de idiomas possíveis usados para criar aplicativos de manipuladores personalizados, o suporte não é ilimitado.
O suporte estará disponível caso o host do Functions tenha problemas para iniciar ou se comunicar com o processo do manipulador personalizado. Para problemas específicos do funcionamento interno do processo de manipulador personalizado, como problemas com a linguagem ou estrutura escolhida, nossa equipe de suporte não pode fornecer assistência nesse contexto.
Próximas etapas
Comece a criar um aplicativo do Azure Functions em Go ou Rust com o guia de início rápido dos manipuladores personalizados.