Guida per sviluppatori di Node.js di Funzioni di Azure
Questa guida è un'introduzione allo sviluppo di Funzioni di Azure usando JavaScript o TypeScript. L'articolo presuppone che l'utente abbia già letto la guida per sviluppatori Funzioni di Azure.
Importante
Il contenuto di questo articolo cambia in base alla scelta del modello di programmazione Node.js nel selettore nella parte superiore di questa pagina. La versione scelta deve corrispondere alla versione del @azure/functions
pacchetto npm in uso nell'app. Se il pacchetto non è elencato in package.json
, il valore predefinito è v3. Altre informazioni sulle differenze tra v3 e v4 sono disponibili nella guida alla migrazione.
Gli sviluppatori di Node.js potrebbero essere interessati anche a uno degli articoli seguenti:
Introduzione | Concetti | Formazione guidata |
---|---|---|
Considerazioni
- Il modello di programmazione Node.js non deve essere confuso con il runtime di Funzioni di Azure:
- Modello di programmazione: definisce come creare il codice ed è specifico di JavaScript e TypeScript.
- Runtime: definisce il comportamento sottostante di Funzioni di Azure e viene condiviso in tutti i linguaggi.
- La versione del modello di programmazione è strettamente associata alla versione del
@azure/functions
pacchetto npm. Il controllo delle versioni viene eseguito indipendentemente dal runtime. Sia il runtime che il modello di programmazione usano il numero 4 come versione principale più recente, ma questa è una coincidenza. - Non è possibile combinare i modelli di programmazione v3 e v4 nella stessa app per le funzioni. Non appena si registra una funzione v4 nell'app, tutte le funzioni v3 registrate nei file function.json vengono ignorate.
Versioni supportate
La tabella seguente illustra ogni versione del modello di programmazione Node.js insieme alle versioni supportate del runtime di Funzioni di Azure e Node.js.
Versione del modello di programmazione | Livello di supporto | Versione del runtime di Funzioni | versione Node.js | Descrizione |
---|---|---|---|---|
4.x | Disponibilità generale | 4.25+ | 20.x, 18.x | Supporta una struttura di file flessibile e un approccio incentrato sul codice per trigger e associazioni. |
3.x | Disponibilità generale | 4.x | 20.x, 18.x, 16.x, 14.x | Richiede una struttura di file specifica con i trigger e le associazioni dichiarati in un file "function.json" |
2.x | n/d | 3.x | 14.x, 12.x, 10.x | È stata raggiunta la fine del supporto il 13 dicembre 2022. Per altre informazioni, vedi Versioni di Funzioni. |
1.x | n/d | 2.x | 10.x, 8.x | È stata raggiunta la fine del supporto il 13 dicembre 2022. Per altre informazioni, vedi Versioni di Funzioni. |
Struttura delle cartelle
La struttura di cartelle richiesta per un progetto JavaScript è simile all'esempio seguente:
<project_root>/
| - .vscode/
| - node_modules/
| - myFirstFunction/
| | - index.js
| | - function.json
| - mySecondFunction/
| | - index.js
| | - function.json
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
La cartella principale del progetto, <project_root>, può contenere i file seguenti:
- .vscode/: (facoltativo) Contiene la configurazione di Visual Studio Code archiviata. Per altre informazioni, vedere Impostazioni di Visual Studio Code.
- myFirstFunction/function.json: contiene la configurazione per il trigger, gli input e gli output della funzione. Il nome della directory determina il nome della funzione.
- myFirstFunction/index.js: archivia il codice della funzione. Per modificare questo percorso di file predefinito, vedere uso di scriptFile.
- .funcignore: (facoltativo) Dichiara i file che non devono essere pubblicati in Azure. In genere, questo file contiene vscode/ per ignorare l'impostazione dell'editor, il test/ per ignorare i test case e local.settings.json per impedire la pubblicazione delle impostazioni dell'app locale.
- host.json: contiene opzioni di configurazione che influiscono su tutte le funzioni in un'istanza dell'app per le funzioni. Questo file viene pubblicato in Azure. Non tutte le opzioni sono supportate durante l'esecuzione in locale. Per altre informazioni, vedere host.json.
- local.settings.json: usato per archiviare le impostazioni e i stringa di connessione dell'app quando è in esecuzione in locale. Questo file non viene pubblicato in Azure. Per altre informazioni, vedere local.settings.file.
- package.json: contiene opzioni di configurazione come un elenco di dipendenze dei pacchetti, il punto di ingresso principale e gli script.
La struttura di cartelle consigliata per un progetto JavaScript è simile all'esempio seguente:
<project_root>/
| - .vscode/
| - node_modules/
| - src/
| | - functions/
| | | - myFirstFunction.js
| | | - mySecondFunction.js
| - test/
| | - functions/
| | | - myFirstFunction.test.js
| | | - mySecondFunction.test.js
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
La cartella principale del progetto, <project_root>, può contenere i file seguenti:
- .vscode/: (facoltativo) Contiene la configurazione di Visual Studio Code archiviata. Per altre informazioni, vedere Impostazioni di Visual Studio Code.
- src/functions/: percorso predefinito per tutte le funzioni e i relativi trigger e associazioni correlati.
- test/: (facoltativo) Contiene i test case dell'app per le funzioni.
- .funcignore: (facoltativo) Dichiara i file che non devono essere pubblicati in Azure. In genere, questo file contiene vscode/ per ignorare l'impostazione dell'editor, il test/ per ignorare i test case e local.settings.json per impedire la pubblicazione delle impostazioni dell'app locale.
- host.json: contiene opzioni di configurazione che influiscono su tutte le funzioni in un'istanza dell'app per le funzioni. Questo file viene pubblicato in Azure. Non tutte le opzioni sono supportate durante l'esecuzione in locale. Per altre informazioni, vedere host.json.
- local.settings.json: usato per archiviare le impostazioni e i stringa di connessione dell'app quando è in esecuzione in locale. Questo file non viene pubblicato in Azure. Per altre informazioni, vedere local.settings.file.
- package.json: contiene opzioni di configurazione come un elenco di dipendenze dei pacchetti, il punto di ingresso principale e gli script.
Registrazione di una funzione
Il modello v3 registra una funzione in base all'esistenza di due file. Prima di tutto, è necessario un function.json
file che si trova in una cartella di un livello inferiore dalla radice dell'app. In secondo luogo, è necessario un file JavaScript che esporta la funzione. Per impostazione predefinita, il modello cerca un index.js
file nella stessa cartella di function.json
. Se si usa TypeScript, è necessario usare la scriptFile
proprietà in function.json
per puntare al file JavaScript compilato. Per personalizzare il percorso del file o il nome di esportazione della funzione, vedere Configurazione del punto di ingresso della funzione.
La funzione esportata deve essere sempre dichiarata come nel async function
modello v3. È possibile esportare una funzione sincrona, ma è necessario chiamare context.done()
per segnalare che la funzione è stata completata, che è deprecata e non consigliata.
La funzione viene passata come context
primo argomento e gli input come argomenti rimanenti.
L'esempio seguente è una funzione semplice che registra che è stata attivata e risponde con Hello, world!
:
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"name": "req",
"authLevel": "anonymous",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
module.exports = async function (context, request) {
context.log('Http function was triggered.');
context.res = { body: 'Hello, world!' };
};
Il modello di programmazione carica le funzioni in base al campo dell'oggetto main
package.json
. È possibile impostare il main
campo su un singolo file o più file usando un modello GLOB. La tabella seguente mostra i valori di esempio per il main
campo:
Esempio | Descrizione |
---|---|
src/index.js |
Registrare le funzioni da un singolo file radice. |
src/functions/*.js |
Registrare ogni funzione dal proprio file. |
src/{index.js,functions/*.js} |
Combinazione in cui si registra ogni funzione dal proprio file, ma è ancora disponibile un file radice per il codice generale a livello di app. |
Per registrare una funzione, è necessario importare l'oggetto app
dal @azure/functions
modulo npm e chiamare il metodo specifico per il tipo di trigger. Il primo argomento durante la registrazione di una funzione è il nome della funzione. Il secondo argomento è un options
oggetto che specifica la configurazione per il trigger, il gestore e qualsiasi altro input o output. In alcuni casi in cui la configurazione del trigger non è necessaria, è possibile passare il gestore direttamente come secondo argomento anziché come options
oggetto .
La registrazione di una funzione può essere eseguita da qualsiasi file nel progetto, purché tale file venga caricato (direttamente o indirettamente) in base al main
campo nel package.json
file. La funzione deve essere registrata in un ambito globale perché non è possibile registrare le funzioni dopo l'avvio delle esecuzioni.
L'esempio seguente è una funzione semplice che registra che è stata attivata e risponde con Hello, world!
:
const { app } = require('@azure/functions');
app.http('helloWorld1', {
methods: ['POST', 'GET'],
handler: async (request, context) => {
context.log('Http function was triggered.');
return { body: 'Hello, world!' };
}
});
Input e output
La funzione è necessaria per avere esattamente un input primario denominato trigger. Può anche avere input e/o output secondari. Gli input e gli output sono configurati nei function.json
file e vengono definiti anche associazioni.
Input
Gli input sono associazioni con direction
impostato su in
. La differenza principale tra un trigger e un input secondario consiste nel fatto che per type
un trigger termina in Trigger
, ad esempio tipo vs tipo blobTrigger
blob
. La maggior parte delle funzioni usa solo un trigger e non molti tipi di input secondari sono supportati.
È possibile accedere agli input in diversi modi:
[Scelta consigliata] Come argomenti passati alla funzione: usare gli argomenti nello stesso ordine in cui sono definiti in
function.json
. Laname
proprietà definita infunction.json
non deve corrispondere al nome dell'argomento, anche se è consigliata per l'organizzazione.module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
Come proprietà di
context.bindings
: usare la chiave corrispondente allaname
proprietà definita infunction.json
.module.exports = async function (context) { context.log("This is myTrigger: " + context.bindings.myTrigger); context.log("This is myInput: " + context.bindings.myInput); context.log("This is myOtherInput: " + context.bindings.myOtherInput); };
Output
Gli output sono binding con direction
impostato su out
e possono essere impostati in diversi modi:
[Consigliato per un singolo output] Restituisce direttamente il valore: se si usa una funzione asincrona, è possibile restituire direttamente il valore. È necessario modificare la
name
proprietà dell'associazione di output in$return
in comefunction.json
nell'esempio seguente:{ "name": "$return", "type": "http", "direction": "out" }
module.exports = async function (context, request) { return { body: "Hello, world!" }; }
[Consigliato per più output] Restituisce un oggetto contenente tutti gli output: se si usa una funzione asincrona, è possibile restituire un oggetto con una proprietà corrispondente al nome di ogni associazione nell'oggetto
function.json
. L'esempio seguente usa associazioni di output denominate "httpResponse" e "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }
module.exports = async function (context, request) { let message = 'Hello, world!'; return { httpResponse: { body: message }, queueOutput: message }; };
Impostare i valori in
context.bindings
: se non si usa una funzione asincrona o non si vogliono usare le opzioni precedenti, è possibile impostare i valori direttamente sucontext.bindings
, dove la chiave corrisponde al nome dell'associazione. L'esempio seguente usa associazioni di output denominate "httpResponse" e "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }
module.exports = async function (context, request) { let message = 'Hello, world!'; context.bindings.httpResponse = { body: message }; context.bindings.queueOutput = message; };
Tipo di dati delle associazioni
È possibile usare la dataType
proprietà in un'associazione di input per modificare il tipo di input, ma presenta alcune limitazioni:
- In Node.js solo
string
ebinary
sono supportati (stream
non è) - Per gli input HTTP, la
dataType
proprietà viene ignorata. Usare invece le proprietà sull'oggettorequest
per ottenere il corpo nel formato desiderato. Per altre informazioni, vedere Richiesta HTTP.
Nell'esempio seguente di un trigger della coda di archiviazione, il tipo predefinito di myQueueItem
è , string
ma se si imposta su dataType
binary
, il tipo passa a un Node.js Buffer
.
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"queueName": "helloworldqueue",
"connection": "storage_APPSETTING",
"dataType": "binary"
}
const { Buffer } = require('node:buffer');
module.exports = async function (context, myQueueItem) {
if (typeof myQueueItem === 'string') {
context.log('myQueueItem is a string');
} else if (Buffer.isBuffer(myQueueItem)) {
context.log('myQueueItem is a buffer');
}
};
La funzione è necessaria per avere esattamente un input primario denominato trigger. Può anche avere input secondari, un output primario denominato output restituito e/o output secondari. Gli input e gli output vengono definiti anche associazioni esterne al contesto del modello di programmazione Node.js. Prima della versione 4 del modello, queste associazioni sono state configurate nei function.json
file.
Input del trigger
Il trigger è l'unico input o output necessario. Per la maggior parte dei tipi di trigger, si registra una funzione usando un metodo sull'oggetto app
denominato dopo il tipo di trigger. È possibile specificare la configurazione specifica del trigger direttamente nell'argomento options
. Ad esempio, un trigger HTTP consente di specificare una route. Durante l'esecuzione, il valore corrispondente a questo trigger viene passato come primo argomento al gestore.
const { app } = require('@azure/functions');
app.http('helloWorld1', {
route: 'hello/world',
handler: async (request, context) => {
...
}
});
Restituire l'output
L'output restituito è facoltativo e in alcuni casi configurato per impostazione predefinita. Ad esempio, un trigger HTTP registrato con app.http
è configurato per restituire automaticamente un output di risposta HTTP. Per la maggior parte dei tipi di output, specificare la configurazione restituita nell'argomento options
con l'aiuto dell'oggetto output
esportato dal @azure/functions
modulo. Durante l'esecuzione, l'output viene impostato restituendolo dal gestore.
L'esempio seguente usa un trigger timer e un output della coda di archiviazione:
const { app, output } = require('@azure/functions');
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: output.storageQueue({
connection: 'storage_APPSETTING',
...
}),
handler: (myTimer, context) => {
return { hello: 'world' }
}
});
Input e output aggiuntivi
Oltre al trigger e alla restituzione, è possibile specificare input o output aggiuntivi sull'argomento durante la options
registrazione di una funzione. Gli input
oggetti e output
esportati dal @azure/functions
modulo forniscono metodi specifici del tipo per creare la configurazione. Durante l'esecuzione, si ottengono o impostano i valori con context.extraInputs.get
o context.extraOutputs.set
, passando l'oggetto di configurazione originale come primo argomento.
L'esempio seguente è una funzione attivata da una coda di archiviazione, con un input BLOB di archiviazione aggiuntivo copiato in un output DEL BLOB di archiviazione aggiuntivo. Il messaggio della coda deve essere il nome di un file e sostituisce {queueTrigger}
come nome del BLOB da copiare, con l'aiuto di un'espressione di associazione.
const { app, input, output } = require('@azure/functions');
const blobInput = input.storageBlob({
connection: 'storage_APPSETTING',
path: 'helloworld/{queueTrigger}',
});
const blobOutput = output.storageBlob({
connection: 'storage_APPSETTING',
path: 'helloworld/{queueTrigger}-copy',
});
app.storageQueue('copyBlob1', {
queueName: 'copyblobqueue',
connection: 'storage_APPSETTING',
extraInputs: [blobInput],
extraOutputs: [blobOutput],
handler: (queueItem, context) => {
const blobInputValue = context.extraInputs.get(blobInput);
context.extraOutputs.set(blobOutput, blobInputValue);
}
});
Input e output generici
Gli app
oggetti , trigger
, input
e output
esportati dal modulo forniscono metodi specifici del tipo per la @azure/functions
maggior parte dei tipi. Per tutti i tipi non supportati, viene fornito un generic
metodo per consentire di specificare manualmente la configurazione. Il generic
metodo può essere usato anche se si desidera modificare le impostazioni predefinite fornite da un metodo specifico del tipo.
L'esempio seguente è una semplice funzione attivata tramite HTTP usando metodi generici anziché metodi specifici del tipo.
const { app, output, trigger } = require('@azure/functions');
app.generic('helloWorld1', {
trigger: trigger.generic({
type: 'httpTrigger',
methods: ['GET', 'POST']
}),
return: output.generic({
type: 'http'
}),
handler: async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
return { body: `Hello, world!` };
}
});
Contesto di chiamata
Ogni chiamata della funzione viene passata a un oggetto chiamata context
, usato per leggere gli input, impostare output, scrivere nei log e leggere vari metadati. Nel modello v3 l'oggetto contesto è sempre il primo argomento passato al gestore.
Di seguito sono elencate le proprietà dell'oggetto context
:
Proprietà | Descrizione |
---|---|
invocationId |
ID della chiamata alla funzione corrente. |
executionContext |
Vedere contesto di esecuzione. |
bindings |
Vedere binding. |
bindingData |
Metadati relativi all'input del trigger per questa chiamata, non incluso il valore stesso. Ad esempio, un trigger dell'hub eventi ha una enqueuedTimeUtc proprietà . |
traceContext |
Contesto per la traccia distribuita. Per ulteriori informazioni, vedere Trace Context . |
bindingDefinitions |
Configurazione degli input e degli output, come definito in function.json . |
req |
Vedere Richiesta HTTP. |
res |
Vedere Risposta HTTP. |
context.executionContext
Di seguito sono elencate le proprietà dell'oggetto context.executionContext
:
Proprietà | Descrizione |
---|---|
invocationId |
ID della chiamata alla funzione corrente. |
functionName |
Nome della funzione richiamata. Il nome della cartella contenente il function.json file determina il nome della funzione. |
functionDirectory |
Cartella contenente il function.json file. |
retryContext |
Vedere contesto di ripetizione dei tentativi. |
context.executionContext.retryContext
Di seguito sono elencate le proprietà dell'oggetto context.executionContext.retryContext
:
Proprietà | Descrizione |
---|---|
retryCount |
Numero che rappresenta il tentativo di ripetizione corrente. |
maxRetryCount |
Numero massimo di tentativi di esecuzione. Valore di -1 mezzi per riprovare per un periodo illimitato. |
exception |
Eccezione che ha causato il nuovo tentativo. |
context.bindings
L'oggetto context.bindings
viene usato per leggere gli input o impostare output. L'esempio seguente è un trigger della coda di archiviazione, che usa context.bindings
per copiare un input del BLOB di archiviazione in un output del BLOB di archiviazione. Il contenuto del messaggio della coda sostituisce {queueTrigger}
come nome file da copiare, con l'aiuto di un'espressione di associazione.
{
"name": "myQueueItem",
"type": "queueTrigger",
"direction": "in",
"connection": "storage_APPSETTING",
"queueName": "helloworldqueue"
},
{
"name": "myInput",
"type": "blob",
"direction": "in",
"connection": "storage_APPSETTING",
"path": "helloworld/{queueTrigger}"
},
{
"name": "myOutput",
"type": "blob",
"direction": "out",
"connection": "storage_APPSETTING",
"path": "helloworld/{queueTrigger}-copy"
}
module.exports = async function (context, myQueueItem) {
const blobValue = context.bindings.myInput;
context.bindings.myOutput = blobValue;
};
context.done
Il context.done
metodo è deprecato. Prima che le funzioni asincrone siano supportate, è necessario segnalare che la funzione viene eseguita chiamando context.done()
:
module.exports = function (context, request) {
context.log("this pattern is now deprecated");
context.done();
};
A questo punto, è consigliabile rimuovere la chiamata a context.done()
e contrassegnare la funzione come asincrona in modo che restituisca una promessa (anche se non await
si ha nulla). Al termine della funzione (in altre parole, la promessa restituita viene risolta), il modello v3 sa che viene eseguita la funzione.
module.exports = async function (context, request) {
context.log("you don't need context.done or an awaited call")
};
Ogni chiamata della funzione viene passata a un oggetto di context
chiamata, con informazioni sulla chiamata e sui metodi usati per la registrazione. Nel modello v4 l'oggetto context
è in genere il secondo argomento passato al gestore.
La InvocationContext
classe ha le proprietà seguenti:
Proprietà | Descrizione |
---|---|
invocationId |
ID della chiamata alla funzione corrente. |
functionName |
Nome della funzione. |
extraInputs |
Usato per ottenere i valori di input aggiuntivi. Per altre informazioni, vedere Input e output aggiuntivi. |
extraOutputs |
Utilizzato per impostare i valori di output aggiuntivi. Per altre informazioni, vedere Input e output aggiuntivi. |
retryContext |
Vedere contesto di ripetizione dei tentativi. |
traceContext |
Contesto per la traccia distribuita. Per ulteriori informazioni, vedere Trace Context . |
triggerMetadata |
Metadati relativi all'input del trigger per questa chiamata, non incluso il valore stesso. Ad esempio, un trigger dell'hub eventi ha una enqueuedTimeUtc proprietà . |
options |
Le opzioni usate durante la registrazione della funzione, dopo che sono state convalidate e con le impostazioni predefinite specificate in modo esplicito. |
Contesto di ripetizione dei tentativi
Di seguito sono elencate le proprietà dell'oggetto retryContext
:
Proprietà | Descrizione |
---|---|
retryCount |
Numero che rappresenta il tentativo di ripetizione corrente. |
maxRetryCount |
Numero massimo di tentativi di esecuzione. Valore di -1 mezzi per riprovare per un periodo illimitato. |
exception |
Eccezione che ha causato il nuovo tentativo. |
Per ulteriori informazioni, vedere retry-policies
.
Registrazione
In Funzioni di Azure è consigliabile usare context.log()
per scrivere i log. Funzioni di Azure si integra con app Azure lication Insights per acquisire meglio i log dell'app per le funzioni. Application Insights, parte di Monitoraggio di Azure, offre funzionalità per la raccolta, il rendering visivo e l'analisi dei log applicazioni e degli output di traccia. Per altre informazioni, vedere Monitoraggio Funzioni di Azure.
Nota
Se si usa il metodo di Node.js console.log
alternativo, questi log vengono rilevati a livello di app e non verranno associati a alcuna funzione specifica. È consigliabile usare context
per la registrazione invece di console
in modo che tutti i log siano associati a una funzione specifica.
Nell'esempio seguente viene scritto un log a livello di "informazioni" predefinito, incluso l'ID chiamata:
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);
Livelli di registrazione
Oltre al metodo predefinito context.log
, sono disponibili i metodi seguenti che consentono di scrivere log a livelli specifici:
metodo | Descrizione |
---|---|
context.log.error() |
Scrive un evento a livello di errore nei log. |
context.log.warn() |
Scrive un evento a livello di avviso nei log. |
context.log.info() |
Scrive un evento a livello di informazioni nei log. |
context.log.verbose() |
Scrive un evento a livello di traccia nei log. |
metodo | Descrizione |
---|---|
context.trace() |
Scrive un evento a livello di traccia nei log. |
context.debug() |
Scrive un evento a livello di debug nei log. |
context.info() |
Scrive un evento a livello di informazioni nei log. |
context.warn() |
Scrive un evento a livello di avviso nei log. |
context.error() |
Scrive un evento a livello di errore nei log. |
Configurare il livello di log
Funzioni di Azure consente di definire il livello di soglia da usare durante il rilevamento e la visualizzazione dei log. Per impostare la soglia, utilizzare la logging.logLevel
proprietà nel host.json
file . Questa proprietà consente di definire un livello predefinito applicato a tutte le funzioni o una soglia per ogni singola funzione. Per altre informazioni, vedere Come configurare il monitoraggio per Funzioni di Azure.
Tenere traccia dei dati personalizzati
Per impostazione predefinita, Funzioni di Azure scrive l'output come tracce in Application Insights. Per un maggiore controllo, è invece possibile usare Application Insights Node.js SDK per inviare dati personalizzati all'istanza di Application Insights.
const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;
module.exports = async function (context, request) {
// Use this with 'tagOverrides' to correlate custom logs to the parent function invocation.
var operationIdOverride = {"ai.operation.id":context.traceContext.traceparent};
client.trackEvent({name: "my custom event", tagOverrides:operationIdOverride, properties: {customProperty2: "custom property value"}});
client.trackException({exception: new Error("handled exceptions can be logged with this method"), tagOverrides:operationIdOverride});
client.trackMetric({name: "custom metric", value: 3, tagOverrides:operationIdOverride});
client.trackTrace({message: "trace message", tagOverrides:operationIdOverride});
client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:231, resultCode:0, success: true, dependencyTypeName: "ZSQL", tagOverrides:operationIdOverride});
client.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true, tagOverrides:operationIdOverride});
};
Il parametro tagOverrides
imposta operation_Id
sull'ID di chiamata alla funzione. Questa impostazione consente di correlare tutti i log generati e personalizzati automaticamente per una determinata chiamata di funzione.
Trigger HTTP
I trigger HTTP e webhook usano oggetti richiesta e risposta per rappresentare i messaggi HTTP.
I trigger HTTP e webhook usano HttpRequest
oggetti e HttpResponse
per rappresentare i messaggi HTTP. Le classi rappresentano un subset dello standard di recupero, usando il pacchetto di undici
Node.js.
Richiesta HTTP
È possibile accedere alla richiesta in diversi modi:
Come secondo argomento della funzione:
module.exports = async function (context, request) { context.log(`Http function processed request for url "${request.url}"`);
context.req
Dalla proprietà :module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.req.url}"`);
Dalle associazioni di input denominate: questa opzione funziona come qualsiasi associazione non HTTP. Il nome dell'associazione in
function.json
deve corrispondere alla chiave incontext.bindings
o "request1" nell'esempio seguente:{ "name": "request1", "type": "httpTrigger", "direction": "in", "authLevel": "anonymous", "methods": [ "get", "post" ] }
module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
Di seguito sono elencate le proprietà dell'oggetto HttpRequest
:
Proprietà | Type | Descrizione |
---|---|---|
method |
string |
Metodo di richiesta HTTP usato per richiamare questa funzione. |
url |
string |
URL della richiesta. |
headers |
Record<string, string> |
Intestazioni di richiesta HTTP. Questo oggetto fa distinzione tra maiuscole e minuscole. È consigliabile usare request.getHeader('header-name') invece , senza distinzione tra maiuscole e minuscole. |
query |
Record<string, string> |
Chiavi e valori dei parametri della stringa di query dall'URL. |
params |
Record<string, string> |
Indirizzare chiavi e valori dei parametri. |
user |
HttpRequestUser | null |
Oggetto che rappresenta l'utente connesso, tramite l'autenticazione di Funzioni, l'autenticazione SWA o null quando tale utente non è connesso. |
body |
Buffer | string | any |
Se il tipo di supporto è "application/octet-stream" o "multipart/*", body è un buffer. Se il valore è una stringa in grado di analizzare JSON, body è l'oggetto analizzato. In caso contrario, body è una stringa. |
rawBody |
string |
Corpo come stringa. Nonostante il nome, questa proprietà non restituisce un buffer. |
bufferBody |
Buffer |
Corpo come buffer. |
È possibile accedere alla richiesta come primo argomento al gestore per una funzione attivata da HTTP.
async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
Di seguito sono elencate le proprietà dell'oggetto HttpRequest
:
Proprietà | Type | Descrizione |
---|---|---|
method |
string |
Metodo di richiesta HTTP usato per richiamare questa funzione. |
url |
string |
URL della richiesta. |
headers |
Headers |
Intestazioni di richiesta HTTP. |
query |
URLSearchParams |
Chiavi e valori dei parametri della stringa di query dall'URL. |
params |
Record<string, string> |
Indirizzare chiavi e valori dei parametri. |
user |
HttpRequestUser | null |
Oggetto che rappresenta l'utente connesso, tramite l'autenticazione di Funzioni, l'autenticazione SWA o null quando tale utente non è connesso. |
body |
ReadableStream | null |
Corpo come flusso leggibile. |
bodyUsed |
boolean |
Valore booleano che indica se il corpo è già letto. |
Per accedere al corpo di una richiesta o di una risposta, è possibile usare i metodi seguenti:
metodo | Tipo restituito |
---|---|
arrayBuffer() |
Promise<ArrayBuffer> |
blob() |
Promise<Blob> |
formData() |
Promise<FormData> |
json() |
Promise<unknown> |
text() |
Promise<string> |
Nota
Le funzioni del corpo possono essere eseguite una sola volta; le chiamate successive verranno risolte con stringhe vuote/ArrayBuffers.
Risposta HTTP
La risposta può essere impostata in diversi modi:
Impostare la
context.res
proprietà :module.exports = async function (context, request) { context.res = { body: `Hello, world!` };
Restituisce la risposta: se la funzione è asincrona e si imposta il nome dell'associazione su
$return
infunction.json
, è possibile restituire direttamente la risposta anziché impostarla sucontext
.{ "type": "http", "direction": "out", "name": "$return" }
module.exports = async function (context, request) { return { body: `Hello, world!` };
Impostare l'associazione di output denominata: questa opzione funziona come qualsiasi associazione non HTTP. Il nome dell'associazione in
function.json
deve corrispondere alla chiave incontext.bindings
o "response1" nell'esempio seguente:{ "type": "http", "direction": "out", "name": "response1" }
module.exports = async function (context, request) { context.bindings.response1 = { body: `Hello, world!` };
Chiamata
context.res.send()
: questa opzione è deprecata. Chiama in modocontext.done()
implicito e non può essere usato in una funzione asincrona.module.exports = function (context, request) { context.res.send(`Hello, world!`);
Se si crea un nuovo oggetto quando si imposta la risposta, tale oggetto deve corrispondere all'interfaccia HttpResponseSimple
, che ha le proprietà seguenti:
Proprietà | Type | Descrizione |
---|---|---|
headers |
Record<string, string> (facoltativo) |
Intestazioni di risposta HTTP. |
cookies |
Cookie[] (facoltativo) |
Cookie di risposta HTTP. |
body |
any (facoltativo) |
Corpo della risposta HTTP. |
statusCode |
number (facoltativo) |
Codice di stato della risposta HTTP. Se non è impostato, il valore predefinito è 200 . |
status |
number (facoltativo) |
Uguale a statusCode . Questa proprietà viene ignorata se statusCode è impostata. |
È anche possibile modificare l'oggetto context.res
senza sovrascriverlo. L'oggetto predefinito context.res
usa l'interfaccia HttpResponseFull
, che supporta i metodi seguenti oltre alle HttpResponseSimple
proprietà :
metodo | Descrizione |
---|---|
status() |
Imposta lo stato. |
setHeader() |
Imposta un campo di intestazione. NOTA: res.set() e res.header() sono supportati e fanno la stessa cosa. |
getHeader() |
Ottenere un campo di intestazione. NOTA: res.get() è supportato e fa la stessa cosa. |
removeHeader() |
Rimuove un'intestazione. |
type() |
Imposta l'intestazione "content-type". |
send() |
Questo metodo è deprecato. Imposta il corpo e le chiamate context.done() per indicare che una funzione di sincronizzazione è stata completata. NOTA: res.end() è supportato e fa la stessa cosa. |
sendStatus() |
Questo metodo è deprecato. Imposta il codice di stato e le chiamate context.done() per indicare che una funzione di sincronizzazione è stata completata. |
json() |
Questo metodo è deprecato. Imposta "content-type" su "application/json", imposta il corpo e chiama context.done() per indicare che una funzione di sincronizzazione è stata completata. |
La risposta può essere impostata in diversi modi:
Come interfaccia semplice con tipo
HttpResponseInit
: questa opzione è il modo più conciso di restituire risposte.return { body: `Hello, world!` };
L'interfaccia
HttpResponseInit
ha le proprietà seguenti:Proprietà Type Descrizione body
BodyInit
(facoltativo)Corpo della risposta HTTP come uno di ArrayBuffer
,Blob
AsyncIterable<Uint8Array>
,FormData
, ,NodeJS.ArrayBufferView
Iterable<Uint8Array>
,URLSearchParams
,null
, ostring
.jsonBody
any
(facoltativo)Corpo della risposta HTTP serializzabile in JSON. Se impostata, la HttpResponseInit.body
proprietà viene ignorata a favore di questa proprietà.status
number
(facoltativo)Codice di stato della risposta HTTP. Se non è impostato, il valore predefinito è 200
.headers
HeadersInit
(facoltativo)Intestazioni di risposta HTTP. cookies
Cookie[]
(facoltativo)Cookie di risposta HTTP. Come classe con tipo
HttpResponse
: questa opzione fornisce metodi helper per la lettura e la modifica di varie parti della risposta, ad esempio le intestazioni.const response = new HttpResponse({ body: `Hello, world!` }); response.headers.set('content-type', 'application/json'); return response;
La
HttpResponse
classe accetta un argomento facoltativoHttpResponseInit
come argomento per il relativo costruttore e ha le proprietà seguenti:Proprietà Type Descrizione status
number
Codice di stato della risposta HTTP. headers
Headers
Intestazioni di risposta HTTP. cookies
Cookie[]
Cookie di risposta HTTP. body
ReadableStream | null
Corpo come flusso leggibile. bodyUsed
boolean
Valore booleano che indica se il corpo è già stato letto.
Flussi HTTP
I flussi HTTP sono una funzionalità che semplifica l'elaborazione di dati di grandi dimensioni, lo streaming di risposte OpenAI, la distribuzione di contenuto dinamico e il supporto di altri scenari HTTP principali. Consente di trasmettere le richieste e le risposte dagli endpoint HTTP nell'app per le funzioni Node.js. Usare i flussi HTTP negli scenari in cui l'app richiede lo scambio in tempo reale e l'interazione tra client e server tramite HTTP. È anche possibile usare flussi HTTP per ottenere prestazioni e affidabilità ottimali per le app quando si usa HTTP.
Importante
I flussi HTTP non sono supportati nel modello v3. Eseguire l'aggiornamento al modello v4 per usare la funzionalità di streaming HTTP.
I tipi e HttpResponse
esistenti HttpRequest
nel modello di programmazione v4 supportano già vari modi di gestire il corpo del messaggio, incluso come flusso.
Prerequisiti
- Pacchetto
@azure/functions
npm versione 4.3.0 o successiva. - Funzioni di Azure runtime versione 4.28 o successiva.
- Funzioni di Azure Core Tools versione 4.0.5530 o successiva, che contiene la versione di runtime corretta.
Abilitare i flussi
Usare questi passaggi per abilitare i flussi HTTP nell'app per le funzioni in Azure e nei progetti locali:
Se si prevede di trasmettere grandi quantità di dati, modificare l'impostazione
FUNCTIONS_REQUEST_BODY_SIZE_LIMIT
in Azure. La dimensione massima predefinita consentita è104857600
, che limita le richieste a una dimensione di ~100 MB.Per lo sviluppo locale, aggiungere
FUNCTIONS_REQUEST_BODY_SIZE_LIMIT
anche al file local.settings.json.Aggiungere il codice seguente all'app in qualsiasi file incluso nel campo principale.
const { app } = require('@azure/functions'); app.setup({ enableHttpStream: true });
Esempi di flussi
Questo esempio mostra una funzione attivata da HTTP che riceve dati tramite una richiesta HTTP POST e la funzione trasmette questi dati a un file di output specificato:
const { app } = require('@azure/functions');
const { createWriteStream } = require('fs');
const { Writable } = require('stream');
app.http('httpTriggerStreamRequest', {
methods: ['POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
const writeStream = createWriteStream('<output file path>');
await request.body.pipeTo(Writable.toWeb(writeStream));
return { body: 'Done!' };
},
});
Questo esempio mostra una funzione attivata da HTTP che trasmette il contenuto di un file come risposta alle richieste HTTP GET in ingresso:
const { app } = require('@azure/functions');
const { createReadStream } = require('fs');
app.http('httpTriggerStreamResponse', {
methods: ['GET'],
authLevel: 'anonymous',
handler: async (request, context) => {
const body = createReadStream('<input file path>');
return { body };
},
});
Per un'app di esempio pronta per l'esecuzione con flussi, vedere questo esempio in GitHub.
Considerazioni sul flusso
- Usare
request.body
per ottenere il massimo vantaggio dall'uso dei flussi. È comunque possibile continuare a usare metodi comerequest.text()
, che restituiscono sempre il corpo come stringa.
Hook
Gli hook non sono supportati nel modello v3. Eseguire l'aggiornamento al modello v4 per usare gli hook.
Usare un hook per eseguire codice in punti diversi del ciclo di vita Funzioni di Azure. Gli hook vengono eseguiti nell'ordine in cui sono registrati e possono essere registrati da qualsiasi file nell'app. Esistono attualmente due ambiti di hook, il livello "app" e il livello di chiamata.
Hook di chiamata
Gli hook di chiamata vengono eseguiti una volta per ogni chiamata della funzione, prima di un preInvocation
hook o dopo in un postInvocation
hook. Per impostazione predefinita, l'hook viene eseguito per tutti i tipi di trigger, ma è anche possibile filtrare in base al tipo. L'esempio seguente illustra come registrare un hook di chiamata e filtrare in base al tipo di trigger:
const { app } = require('@azure/functions');
app.hook.preInvocation((context) => {
if (context.invocationContext.options.trigger.type === 'httpTrigger') {
context.invocationContext.log(
`preInvocation hook executed for http function ${context.invocationContext.functionName}`
);
}
});
app.hook.postInvocation((context) => {
if (context.invocationContext.options.trigger.type === 'httpTrigger') {
context.invocationContext.log(
`postInvocation hook executed for http function ${context.invocationContext.functionName}`
);
}
});
Il primo argomento del gestore hook è un oggetto di contesto specifico di tale tipo di hook.
Di seguito sono elencate le proprietà dell'oggetto PreInvocationContext
:
Proprietà | Descrizione |
---|---|
inputs |
Argomenti passati alla chiamata. |
functionHandler |
Gestore della funzione per la chiamata. Le modifiche apportate a questo valore influiscono sulla funzione stessa. |
invocationContext |
Oggetto contesto di chiamata passato alla funzione. |
hookData |
Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. È consigliabile usare un nome di proprietà univoco in modo che non sia in conflitto con i dati di altri hook. |
Di seguito sono elencate le proprietà dell'oggetto PostInvocationContext
:
Proprietà | Descrizione |
---|---|
inputs |
Argomenti passati alla chiamata. |
result |
Risultato della funzione. Le modifiche apportate a questo valore influiscono sul risultato complessivo della funzione. |
error |
Errore generato dalla funzione o null/undefined se non è presente alcun errore. Le modifiche apportate a questo valore influiscono sul risultato complessivo della funzione. |
invocationContext |
Oggetto contesto di chiamata passato alla funzione. |
hookData |
Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. È consigliabile usare un nome di proprietà univoco in modo che non sia in conflitto con i dati di altri hook. |
Hook dell'app
Gli hook dell'app vengono eseguiti una volta per ogni istanza dell'app, durante l'avvio in un appStart
hook o durante la terminazione in un appTerminate
hook. Gli hook di terminazione dell'app hanno un tempo limitato per l'esecuzione e non vengono eseguiti in tutti gli scenari.
Il runtime Funzioni di Azure attualmente non supporta la registrazione del contesto all'esterno di una chiamata. Usare il pacchetto npm di Application Insights per registrare i dati durante gli hook a livello di app.
L'esempio seguente registra gli hook dell'app:
const { app } = require('@azure/functions');
app.hook.appStart((context) => {
// add your logic here
});
app.hook.appTerminate((context) => {
// add your logic here
});
Il primo argomento del gestore hook è un oggetto di contesto specifico di tale tipo di hook.
Di seguito sono elencate le proprietà dell'oggetto AppStartContext
:
Proprietà | Descrizione |
---|---|
hookData |
Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. È consigliabile usare un nome di proprietà univoco in modo che non sia in conflitto con i dati di altri hook. |
Di seguito sono elencate le proprietà dell'oggetto AppTerminateContext
:
Proprietà | Descrizione |
---|---|
hookData |
Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. È consigliabile usare un nome di proprietà univoco in modo che non sia in conflitto con i dati di altri hook. |
Scalabilità e concorrenza
Per impostazione predefinita, Funzioni di Azure monitora automaticamente il carico nell'applicazione e crea più istanze host per Node.js in base alle esigenze. Funzioni di Azure usa soglie predefinite (non configurabili dall'utente) per diversi tipi di trigger per decidere quando aggiungere istanze, ad esempio l'età dei messaggi e le dimensioni della coda per QueueTrigger. Per altre informazioni, vedere Come funzionano i piani a consumo e Premium.
Questo comportamento di ridimensionamento è sufficiente per molte applicazioni Node.js. Per le applicazioni associate alla CPU, è possibile migliorare ulteriormente le prestazioni usando più processi di lavoro in linguaggio. È possibile aumentare il numero di processi di lavoro per host dal valore predefinito 1 fino a un massimo di 10 usando l'impostazione dell'applicazione FUNCTIONS_WORKER_PROCESS_COUNT . Funzioni di Azure prova quindi a distribuire uniformemente le chiamate di funzioni simultanee tra questi processi di lavoro. Questo comportamento rende meno probabile che una funzione a elevato utilizzo di CPU impedisca l'esecuzione di altre funzioni. L'impostazione si applica a ogni host che Funzioni di Azure crea quando si aumenta la scalabilità orizzontale dell'applicazione per soddisfare la domanda.
Avviso
Usare l'impostazione FUNCTIONS_WORKER_PROCESS_COUNT
con cautela. Più processi in esecuzione nella stessa istanza possono causare un comportamento imprevedibile e aumentare i tempi di caricamento delle funzioni. Se si usa questa impostazione, è consigliabile compensare questi svantaggi eseguendo da un file di pacchetto.
Versione del nodo
È possibile visualizzare la versione corrente usata dal runtime registrando process.version
da qualsiasi funzione. Vedere supported versions
per un elenco delle versioni Node.js supportate da ogni modello di programmazione.
Impostazione della versione del nodo
Il modo in cui si aggiorna la versione Node.js dipende dal sistema operativo in cui viene eseguita l'app per le funzioni.
Durante l'esecuzione in Windows, la versione Node.js viene impostata dall'impostazione dell'applicazione WEBSITE_NODE_DEFAULT_VERSION
. Questa impostazione può essere aggiornata usando l'interfaccia della riga di comando di Azure o nella portale di Azure.
Per altre informazioni sulle versioni di Node.js, vedere Versioni supportate.
Prima di aggiornare la versione Node.js, assicurarsi che l'app per le funzioni sia in esecuzione nella versione più recente del runtime di Funzioni di Azure. Se è necessario aggiornare la versione del runtime, vedere Eseguire la migrazione delle app da Funzioni di Azure versione 3.x alla versione 4.x.
Eseguire il comando dell'interfaccia della riga di comando di Azure az functionapp config appsettings set
per aggiornare la versione Node.js per l'app per le funzioni in esecuzione in Windows:
az functionapp config appsettings set --settings WEBSITE_NODE_DEFAULT_VERSION=~20 \
--name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>
In questo modo l'applicazione WEBSITE_NODE_DEFAULT_VERSION
imposta la versione LTS supportata di ~20
.
Dopo aver apportato le modifiche, l'app per le funzioni viene riavviata. Per altre informazioni sul supporto delle funzioni per Node.js, vedere Criteri di supporto del runtime del linguaggio.
Variabili di ambiente
Le variabili di ambiente possono essere utili per i segreti operativi (stringa di connessione, chiavi, endpoint e così via) o impostazioni ambientali come le variabili di profilatura. È possibile aggiungere variabili di ambiente sia negli ambienti locali che nel cloud e accedervi tramite process.env
nel codice della funzione.
L'esempio seguente registra la WEBSITE_SITE_NAME
variabile di ambiente:
module.exports = async function (context) {
context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}
async function timerTrigger1(myTimer, context) {
context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}
Nell'ambiente di sviluppo locale
Quando si esegue in locale, il progetto di funzioni include un local.settings.json
file in cui archiviare le variabili di ambiente nell'oggetto Values
.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"CUSTOM_ENV_VAR_1": "hello",
"CUSTOM_ENV_VAR_2": "world"
}
}
Nell'ambiente cloud di Azure
Quando si esegue in Azure, l'app per le funzioni consente di impostare e usare le impostazioni dell'applicazione, ad esempio le stringa di connessione del servizio, ed espone queste impostazioni come variabili di ambiente durante l'esecuzione.
Esistono diversi modi per aggiungere, aggiornare ed eliminare le impostazioni dell'app per le funzioni:
- Nel portale di Azure.
- Tramite l'uso dell'interfaccia della riga di comando di Azure
- Usando Azure PowerShell.
Le modifiche apportate alle impostazioni dell'app per le funzioni richiedono il riavvio dell'app per le funzioni.
Variabili di ambiente del ruolo di lavoro
Esistono diverse variabili di ambiente di Funzioni specifiche per Node.js:
languageWorkers__node__arguments
Questa impostazione consente di specificare argomenti personalizzati all'avvio del processo di Node.js. Viene spesso usato in locale per avviare il ruolo di lavoro in modalità di debug, ma può essere usato anche in Azure se sono necessari argomenti personalizzati.
Avviso
Se possibile, evitare di usare languageWorkers__node__arguments
in Azure perché può avere un effetto negativo sui tempi di inizio a freddo. Invece di usare ruoli di lavoro pre-riscaldati, il runtime deve avviare un nuovo ruolo di lavoro da zero con gli argomenti personalizzati.
logging__logLevel__Worker
Questa impostazione regola il livello di log predefinito per i log di lavoro specifici di Node.js. Per impostazione predefinita, vengono visualizzati solo i log degli avvisi o degli errori, ma è possibile impostarlo su information
o debug
per diagnosticare i problemi relativi al ruolo di lavoro Node.js. Per altre informazioni, vedere Configurazione dei livelli di log.
Moduli ECMAScript (anteprima)
Nota
Poiché i moduli ECMAScript sono attualmente una funzionalità di anteprima in Node.js 14 o versione successiva in Funzioni di Azure.
I moduli ECMAScript (moduli ES) sono il nuovo sistema di moduli standard ufficiale per Node.js. Finora, gli esempi di codice in questo articolo usano la sintassi CommonJS. Quando si esegue Funzioni di Azure in Node.js 14 o versione successiva, è possibile scegliere di scrivere le funzioni usando la sintassi dei moduli ES.
Per usare i moduli ES in una funzione, modificare il nome file in modo da usare un'estensione .mjs
. L'esempio di file index.mjs seguente è una funzione attivata da HTTP che usa la sintassi dei moduli ES per importare la uuid
libreria e restituire un valore.
import { v4 as uuidv4 } from 'uuid';
async function httpTrigger1(context, request) {
context.res.body = uuidv4();
};
export default httpTrigger;
import { v4 as uuidv4 } from 'uuid';
async function httpTrigger1(request, context) {
return { body: uuidv4() };
};
app.http('httpTrigger1', {
methods: ['GET', 'POST'],
handler: httpTrigger1
});
Configurare il punto di ingresso della funzione
È possibile usare le proprietà scriptFile
e entryPoint
di function.json
per configurare il percorso e il nome della funzione esportata. La scriptFile
proprietà è obbligatoria quando si usa TypeScript e deve puntare al codice JavaScript compilato.
uso di scriptFile
Per impostazione predefinita, viene eseguita una funzione JavaScript da index.js
, un file che condivide la stessa directory padre del file function.json
corrispondente.
È possibile usare scriptFile
per ottenere una struttura di cartelle simile a quella nell'esempio seguente:
<project_root>/
| - node_modules/
| - myFirstFunction/
| | - function.json
| - lib/
| | - sayHello.js
| - host.json
| - package.json
Il file function.json
per myFirstFunction
deve includere una proprietà scriptFile
che punta al file con la funzione esportata da eseguire.
{
"scriptFile": "../lib/sayHello.js",
"bindings": [
...
]
}
uso di entryPoint
Nel modello v3, una funzione deve essere esportata usando module.exports
per poter essere trovata ed eseguita. Per impostazione predefinita, la funzione eseguita quando viene attivata è l'unica esportazione dal file, ovvero l'esportazione denominata run
o quella denominata index
. Nell'esempio seguente viene function.json
impostato entryPoint
su un valore personalizzato, "logHello":
{
"entryPoint": "logHello",
"bindings": [
...
]
}
async function logHello(context) {
context.log('Hello, world!');
}
module.exports = { logHello };
Debug locale
È consigliabile usare VS Code per il debug locale, che avvia automaticamente il processo di Node.js in modalità di debug e si collega automaticamente al processo. Per altre informazioni, vedere Eseguire la funzione in locale.
Se si usa uno strumento diverso per il debug o si vuole avviare manualmente il processo di Node.js in modalità di debug, aggiungere "languageWorkers__node__arguments": "--inspect"
in local.settings.json.Values
L'argomento --inspect
indica Node.js di restare in ascolto di un client di debug sulla porta 9229 per impostazione predefinita. Per altre informazioni, vedere la guida al debug Node.js.
Consigli
Questa sezione descrive diversi modelli di impatto per Node.js app che ti consigliamo di seguire.
Scegliere i piani di servizio app con una singola vCPU
Quando si crea un'app per le funzioni che usa il piano di servizio app, è consigliabile selezionare un piano con una singola vCPU anziché uno con più vCPU. Attualmente, Funzioni esegue Node.js funzioni in modo più efficiente nelle macchine virtuali a singola vCPU e l'uso di macchine virtuali di dimensioni maggiori non produce i miglioramenti previsti delle prestazioni. Quando necessario, è possibile aumentare manualmente il numero di istanze di macchine virtuali con scalabilità orizzontale aggiungendo altre istanze di VM a vCPU singola oppure abilitare la scalabilità automatica. Per altre informazioni, vedere Scalare il conteggio delle istanze manualmente o automaticamente.
Eseguire da un file di pacchetto
Quando si sviluppano Funzioni di Azure nel modello di hosting serverless, l'avvio a freddo è una realtà. L'avvio a freddo si riferisce alla prima volta che l'app per le funzioni inizia dopo un periodo di inattività, richiedendo più tempo per l'avvio. Per Node.js app con alberi delle dipendenze di grandi dimensioni, in particolare, l'avvio a freddo può essere significativo. Per velocizzare il processo di avvio a freddo eseguire le funzioni come un file di pacchetto quando possibile. Per impostazione predefinita, molti metodi di distribuzione usano questo modello, ma se si verifica un avvio a freddo di grandi dimensioni, è consigliabile verificare di essere in esecuzione in questo modo.
Usare un singolo client statico
Quando si usa un client specifico del servizio in un'applicazione Funzioni di Azure, non creare un nuovo client con ogni chiamata di funzione perché è possibile raggiungere i limiti di connessione. Creare invece un singolo client statico nell'ambito globale. Per altre informazioni, vedere Gestione delle connessioni in Funzioni di Azure.
Usare async
ed await
Quando si scrivono Funzioni di Azure in Node.js, è necessario scrivere codice usando le async
parole chiave e await
. La scrittura di codice usando async
e await
invece di callback o .then
con .catch
promise consente di evitare due problemi comuni:
- Generazione di eccezioni non rilevate che causano un arresto anomalo del processo di Node.js, che potrebbero influire sull'esecuzione di altre funzioni.
- Comportamento imprevisto, ad esempio log mancanti da
context.log
, causato da chiamate asincrone non attese correttamente.
Nell'esempio seguente il metodo fs.readFile
asincrono viene richiamato con una funzione di callback error-first come secondo parametro. Questo codice causa entrambi i problemi menzionati in precedenza. Un'eccezione non rilevata in modo esplicito nell'ambito corretto può arrestare l'intero processo (problema 1). La restituzione senza garantire il completamento del callback indica che la risposta HTTP a volte avrà un corpo vuoto (problema 2).
// DO NOT USE THIS CODE
const { app } = require('@azure/functions');
const fs = require('fs');
app.http('httpTriggerBadAsync', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
let fileData;
fs.readFile('./helloWorld.txt', (err, data) => {
if (err) {
context.error(err);
// BUG #1: This will result in an uncaught exception that crashes the entire process
throw err;
}
fileData = data;
});
// BUG #2: fileData is not guaranteed to be set before the invocation ends
return { body: fileData };
},
});
Nell'esempio seguente il metodo fs.readFile
asincrono viene richiamato con una funzione di callback error-first come secondo parametro. Questo codice causa entrambi i problemi menzionati in precedenza. Un'eccezione non rilevata in modo esplicito nell'ambito corretto può arrestare l'intero processo (problema 1). La chiamata al metodo deprecato context.done()
all'esterno dell'ambito del callback può segnalare che la funzione viene completata prima della lettura del file (problema 2). In questo esempio, la chiamata context.done()
troppo presto comporta la mancanza di voci di log che iniziano con Data from file:
.
// NOT RECOMMENDED PATTERN
const fs = require('fs');
module.exports = function (context) {
fs.readFile('./hello.txt', (err, data) => {
if (err) {
context.log.error('ERROR', err);
// BUG #1: This will result in an uncaught exception that crashes the entire process
throw err;
}
context.log(`Data from file: ${data}`);
// context.done() should be called here
});
// BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
context.done();
}
Usare le async
parole chiave e await
per evitare entrambi questi problemi. La maggior parte delle API nell'ecosistema Node.js è stata convertita per supportare le promesse in qualche modo. Ad esempio, a partire dalla versione 14, Node.js fornisce un'API fs/promises
per sostituire l'API fs
di callback.
Nell'esempio seguente, tutte le eccezioni non gestite generate durante l'esecuzione della funzione non superano solo la singola chiamata che ha generato l'eccezione. La await
parola chiave indica che i passaggi seguenti vengono readFile
eseguiti solo dopo il completamento.
// Recommended pattern
const { app } = require('@azure/functions');
const fs = require('fs/promises');
app.http('httpTriggerGoodAsync', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (request, context) => {
try {
const fileData = await fs.readFile('./helloWorld.txt');
return { body: fileData };
} catch (err) {
context.error(err);
// This rethrown exception will only fail the individual invocation, instead of crashing the whole process
throw err;
}
},
});
Con async
e await
non è necessario chiamare il context.done()
callback.
// Recommended pattern
const fs = require('fs/promises');
module.exports = async function (context) {
let data;
try {
data = await fs.readFile('./hello.txt');
} catch (err) {
context.log.error('ERROR', err);
// This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
throw err;
}
context.log(`Data from file: ${data}`);
}
Risoluzione dei problemi
Vedere la guida alla risoluzione dei problemi di Node.js.
Passaggi successivi
Per ulteriori informazioni, vedi le seguenti risorse:
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per