Guida di riferimento per sviluppatori Node.js di Funzioni di Azure

Questo riferimento spiega come sviluppare Funzioni di Azure usando JavaScript e TypeScript con il @azure/functions pacchetto npm. Per una panoramica generale dei concetti di Funzioni di Azure condivisi in tutti i linguaggi, consulta il riferimento per sviluppatori di Funzioni di Azure.

Conto risorse Link
Crea la tua prima funzione JavaScript Visual Studio Code/CLI
Crea la tua prima funzione TypeScript Visual Studio Code/CLI
Scenari e esempi JavaScript/TypeScript
Informazioni di riferimento sulle API @azure/functions API

Note

Questo articolo mostra il contenuto di una specifica versione del modello di programmazione basato sul selettore in cima alla pagina. La versione che scegli dovrebbe corrispondere alla versione del pacchetto @azure/functions NPM. Non puoi mescolare le funzioni v3 e v4 nella stessa app. Se non hai il pacchetto nel tuo package.json, il valore predefinito è v3.

Modello di programmazione

Funzioni di Azure per Node.js supporta due versioni di modello di programmazione. I nuovi progetti dovrebbero usare la v4.

Feature v4 (consigliato) v3
Condizione GA GA (manutenzione)
@azure/functions pacchetto 4.x 3.x
Registrazione delle funzioni Incentrato sul codice (app.http(), app.timer()) Basato su file (function.json)
Struttura dei file Flessibile Corretto (una cartella per funzione)
Versione di runtime di Funzioni 4.25+ 4.x
versioni di Node.js 24.x, 22.x 24.x, 22.x

Nel modello di programmazione Node.js v4, si registrano funzioni importando l'oggetto app da @azure/functions e chiamando metodi specifici per trigger. Le funzioni sono definite direttamente nel tuo codice con una struttura file flessibile. Ogni funzione ha un singolo trigger che avvia la sua esecuzione e può anche avere binding, che sono connessioni dichiarative ad altri servizi per leggere i dati di input o scrivere dati di output. Per ulteriori informazioni, vedi trigger e associazioni.

Nel modello v4, tu:

  • Registrare funzioni usando metodi specifici per trigger come app.http(), app.timer(), e app.storageQueue().
  • Accedi al valore di input del trigger come primo parametro del tuo handler (ad esempio, HttpRequest).
  • Restituisci l'output primario direttamente dalla funzione handler.
  • Usa context.extraInputs.get() per leggere da binding di input aggiuntivi come gestione rete virtuale di Azure.
  • Usa context.extraOutputs.set() per scrivere in binding di output aggiuntivi come le code.
  • Ogni funzione ha esattamente un trigger, ma può avere più input e output aggiuntivi.
  • Puoi memorizzare in cache i dati nelle variabili globali per il riutilizzo tra le invocazioni, ma non affidarti a questo stato per persistere. Il tempo di esecuzione può riciclare il tuo lavoratore in qualsiasi momento.

Nel modello di programmazione Node.js v3, si definisce ogni funzione utilizzando un function.json file di configurazione e il corrispondente codice JavaScript o TypeScript. Organizzi le funzioni in cartelle separate con strutture file specifiche. Ogni funzione ha un singolo trigger che avvia la sua esecuzione e può anche avere binding, che sono connessioni dichiarative ad altri servizi per leggere i dati di input o scrivere dati di output. Per altre informazioni, vedere trigger e associazioni.

Nel modello v3, tu:

  • Definisci trigger e binding in un function.json file. Usa direction: "in" sia per ingressi che direction: "out" per uscite.
  • Accedi all'input del trigger come secondo argomento al tuo handler, oppure leggilo da context.bindings.
  • Imposta le uscite assegnando valori a context.bindings (ad esempio, context.bindings.outputQueue). Per HTTP, usa context.res.
  • I progetti TypeScript richiedono una scriptFile proprietà in function.json che punti al file JavaScript compilato.
  • Ogni funzione ha esattamente un trigger, ma può avere più associazioni di input e output.
  • Puoi memorizzare in cache i dati nelle variabili globali per il riutilizzo tra le invocazioni, ma non affidarti a questo stato per persistere. Il tempo di esecuzione può riciclare il tuo lavoratore in qualsiasi momento.

Examples

Ecco una funzione semplice che risponde a una richiesta HTTP:

const { app } = require('@azure/functions');

app.http('httpTrigger', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        context.log('HTTP trigger function processed a request.');

        return { body: `Hello, ${name}!` };
    }
});

Il seguente esempio non-HTTP utilizza un trigger timer:

const { app } = require('@azure/functions');

app.timer('cleanupTimer', {
  schedule: '0 */5 * * * *',
  handler: async (myTimer, context) => {
    context.log('Timer trigger function ran at', new Date().toISOString());
  }
});

Il seguente esempio mostra un trigger HTTP con un binding di uscita in coda:

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
  queueName: 'work-items',
  connection: 'AzureWebJobsStorage'
});

app.http('submitWorkItem', {
  methods: ['POST'],
  extraOutputs: [queueOutput],
  handler: async (request, context) => {
    const body = await request.json();
    context.extraOutputs.set(queueOutput, JSON.stringify(body));
    return { status: 202, jsonBody: { accepted: true } };
  }
});

Ecco una funzione semplice che risponde a una richiesta HTTP:

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    context.log('HTTP trigger function processed a request.');

    context.res = {
        body: `Hello, ${name}!`
    };
};

Il seguente esempio non-HTTP utilizza un trigger timer:

{
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}
module.exports = async function (context, myTimer) {
    context.log('Timer trigger function ran at', new Date().toISOString());
};

Il seguente esempio mostra un trigger HTTP con un binding di uscita in coda:

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["post"]
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "workItems",
      "queueName": "work-items",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}
module.exports = async function (context, req) {
    const payload = req.body || {};
    context.bindings.workItems = JSON.stringify(payload);
    context.res = {
        status: 202,
        body: { accepted: true }
    };
};

Creazione dell'app di funzione

Questa sezione copre i componenti essenziali per creare e strutturare la tua app funzione Node, inclusa la @azure/functions libreria, la struttura del progetto e la gestione dei pacchetti.

Libreria @azure/functions

La @azure/functions libreria TypeScript/JavaScript fornisce i tipi e le funzioni principali che utilizzi per interagire con l'runtime di Funzioni di Azure. Per visualizzare tutti i tipi e i metodi disponibili, visitare l'API@azure/functions.

Il codice della funzione può usare @azure/functions per:

  • Registrare funzioni e definire i trigger (modello v4).
  • Accedi ai dati di input dei trigger con tipizzazione forte (ad esempio, HttpRequest, Timer).
  • Creare valori di output tipati (come HttpResponseInit).
  • Interagire con il contesto fornito dal runtime e i dati di binding.

Se utilizzi @azure/functions nella tua app, includilo tra le dipendenze del progetto:

{
  "dependencies": {
    "@azure/functions": "^4.0.0"
  }
}

Note

La @azure/functions libreria definisce la superficie di programmazione per Node.js Funzioni di Azure, ma non è un SDK generico. Usarlo in modo specifico per la creazione e l'esecuzione di funzioni all'interno del runtime Funzioni di Azure.

Configurazione di TypeScript

Per ottenere la migliore esperienza di sviluppo con TypeScript, assicurati che il tuo tsconfig.json includa la configurazione corretta:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es6",
    "outDir": "dist",
    "rootDir": ".",
    "sourceMap": true,
    "strict": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

Struttura di cartelle

Un progetto JavaScript richiede la struttura di cartelle mostrata nel seguente esempio:

<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 Visual Studio Code archiviata. Per altre informazioni, vedere impostazioni 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. Di solito, questo file contiene .vscode/ per ignorare le impostazioni dell'editor, test/ ignorare casi di test e local.settings.json per impedire la pubblicazione delle impostazioni locali dell'app.
  • host.json: contiene opzioni di configurazione che influiscono su tutte le funzioni in un'istanza dell'app per le funzioni. Questo file viene pubblicato su Azure. Non tutte le opzioni sono supportate durante l'esecuzione in locale. Per altre informazioni, vedere host.json.
  • local.settings.json: viene usato per archiviare le impostazioni dell'app e le stringhe di connessione durante l'esecuzione in locale. Questo file non viene pubblicato in Azure. Per altre informazioni, vedere local.settings.file.
  • package.json: Contiene opzioni di configurazione come una lista delle dipendenze dei pacchetti, il punto di ingresso principale e script.

Un progetto JavaScript segue la struttura di cartelle consigliata nel seguente esempio:

<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 Visual Studio Code archiviata. Per altre informazioni, vedere impostazioni 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. Di solito, questo file contiene .vscode/ per ignorare le impostazioni dell'editor, test/ ignorare casi di test e local.settings.json per impedire la pubblicazione delle impostazioni locali dell'app.
  • host.json: contiene opzioni di configurazione che influiscono su tutte le funzioni in un'istanza dell'app per le funzioni. Questo file viene pubblicato su Azure. Non tutte le opzioni sono supportate durante l'esecuzione in locale. Per altre informazioni, vedere host.json.
  • local.settings.json: viene usato per archiviare le impostazioni dell'app e le stringhe di connessione durante l'esecuzione in locale. Questo file non viene pubblicato in Azure. Per altre informazioni, vedere local.settings.file.
  • package.json: Contiene opzioni di configurazione come una lista delle dipendenze dei pacchetti, il punto di ingresso principale e script.

Gestione dei pacchetti

Una gestione efficace dei pacchetti è fondamentale per Node.js Funzioni di Azure progetti. Questa sezione tratta la gestione delle dipendenze, la configurazione dei pacchetti e le migliori pratiche per mantenere le dipendenze delle tue function app.

Gestione delle dipendenze

Tutti i Node.js Funzioni di Azure progetti usano npm per la gestione dei pacchetti. Il tuo package.json file definisce la configurazione del progetto, le dipendenze e gli script necessari per costruire ed eseguire le tue funzioni.

Struttura essenziale di package.json:

{
  "name": "my-functions-app",
  "version": "1.0.0",
  "description": "Azure Functions Node.js app",
  "main": "src/index.js",
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "prestart": "npm run build",
    "start": "func start",
    "test": "jest"
  },
  "dependencies": {
    "@azure/functions": "^4.0.0"
  },
  "devDependencies": {
    "@azure/functions-core-tools": "^4.0.4670",
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "jest": "^29.0.0"
  }
}

Runtime vs. dipendenze di sviluppo

Separati adeguatamente le tue dipendenze:

Dipendenze di runtime (dependencies):

  • @azure/functions: La libreria principale di Funzioni di Azure
  • Librerie di business logic (lodash, axios e pacchetti simili)
  • Driver di database (mongodb, mssql e pacchetti simili)
  • Azure SDK pacchetti (@azure/storage-blob, @azure/cosmos, e pacchetti simili)

Dipendenze di sviluppo (devDependencies):

  • Compilatore TypeScript e definizioni di tipo
  • Framework di test (Jest, Mocha)
  • Strumenti di build e linter
  • Funzioni di Azure Core Tools (per lo sviluppo locale)

Pacchetti specifici per TypeScript

Per i progetti TypeScript, includere queste dipendenze essenziali di sviluppo:

{
  "devDependencies": {
    "@types/node": "^18.0.0",
    "typescript": "^4.0.0",
    "@typescript-eslint/eslint-plugin": "^5.0.0",
    "@typescript-eslint/parser": "^5.0.0"
  }
}

Sicurezza e aggiornamenti

Aggiorna regolarmente le tue dipendenze per affrontare vulnerabilità di sicurezza:

# Check for outdated packages
npm outdated

# Update packages
npm update

# Audit for security issues
npm audit
npm audit fix

Esecuzione e debug

Questa sezione copre lo sviluppo locale, le tecniche di debug e le strategie di test per Node.js Funzioni di Azure.

Configurazione di sviluppo locale

Prerequisiti:

Procedura di configurazione:

  1. Installare le dipendenze:

    npm install
    
  2. Compila i progetti TypeScript:

    npm run build
    
  3. Avvia l'esecuzione locale:

    npm start
    # or directly:
    func start
    

Configurazione dell'ambiente

Configura il tuo ambiente di sviluppo locale utilizzando local.settings.json:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "NODE_ENV": "development",
    "CUSTOM_ENV_VARIABLE": "local-value"
  },
  "Host": {
    "LocalHttpPort": 7071,
    "CORS": "*",
    "CORSCredentials": false
  }
}

Debugging

Debug di Visual Studio Code:

Creare .vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Attach to Node Functions",
      "type": "node",
      "request": "attach",
      "port": 9229,
      "preLaunchTask": "func: host start"
    }
  ]
}

Creare .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "type": "func",
      "label": "func: host start",
      "command": "host start",
      "problemMatcher": "$func-node-watch",
      "isBackground": true,
      "options": {
        "cwd": "${workspaceFolder}"
      }
    }
  ]
}

Debug in linea di comando:

# Start with debugging enabled
func start --p <port>

# For TypeScript, ensure you build first
npm run build
func start --p 9229

Distribuzione

Questa sezione copre le strategie di deployment, l'integrazione CI/CD e le migliori pratiche di produzione per Node.js Funzioni di Azure.

Metodi di distribuzione

1. Distribuzione di Visual Studio Code:

  • Installa l'estensione Funzioni di Azure.
  • Fai clic con il pulsante destro sull'app per le funzioni nel pannello Azure.
  • Selezionare Distribuisci in Function App.

2. Funzioni di Azure Core Tools:

# Deploy to Azure
func azure functionapp publish <FunctionAppName>

# Deploy with custom settings
func azure functionapp publish <FunctionAppName> --build local --publish-local-settings

3. interfaccia della riga di comando di Azure deployment:

# Deploy from local folder
az functionapp deployment source config-zip \
  --resource-group <ResourceGroupName> \
  --name <FunctionAppName> \
  --src <PathToZipFile>

Configurazione di produzione

Impostazioni applicative in Azure:

Configura le variabili ambientali per la produzione:

  • WEBSITE_NODE_DEFAULT_VERSION: impostato su ~18 o ~20.
  • FUNCTIONS_WORKER_RUNTIME: impostare su node.
  • Stringhe di connessione e chiavi API come impostazioni sicure dell'app.
  • NODE_ENV: impostare su production.

Trigger e associazioni

Funzioni di Azure usa trigger per avviare l'esecuzione della funzione e bindings per connettere il codice ad altri servizi come archiviazione, coda e database. Nel modello di programmazione Node.js, dichiari i binding in modo diverso a seconda della versione del modello.

Esistono due tipi principali di associazioni:

  • Trigger (input che avvia la funzione)
  • Input e output (origini dati o destinazioni aggiuntive)

Per altre informazioni sui trigger e le associazioni disponibili, vedere Triggers and Bindings in Funzioni di Azure.

Esempio: Timer Trigger con input Blob

Questa funzione si attiva ogni 10 minuti, legge da un Blob usando input aggiuntivi e registra il contenuto del blob.

const { app, input } = require('@azure/functions');

let CACHED_BLOB_DATA = null;

const blobInput = input.storageBlob({
    connection: 'BLOB_CONNECTION_SETTING',
    path: 'mycontainer/myblob.txt'
});

app.timer('TimerTriggerWithBlob', {
    schedule: '0 */10 * * * *',
    extraInputs: [blobInput],
    handler: async (myTimer, context) => {
        if (CACHED_BLOB_DATA === null) {
            // Read blob content and cache it
            CACHED_BLOB_DATA = context.extraInputs.get(blobInput);
            context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
        }

        context.log(`Timer function executed at: ${new Date().toISOString()}`);
        context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
    }
});

Questa funzione si attiva ogni 10 minuti, legge da un Blob usando la configurazione dei bindings e registra il contenuto del blob.

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "name": "myTimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */10 * * * *"
    },
    {
      "name": "blobInput",
      "type": "blob",
      "direction": "in",
      "path": "mycontainer/myblob.txt",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
let CACHED_BLOB_DATA = null;

module.exports = async function (context, myTimer) {
    if (CACHED_BLOB_DATA === null) {
        // Read blob content and cache it
        CACHED_BLOB_DATA = context.bindings.blobInput;
        context.log(`Blob content cached: ${CACHED_BLOB_DATA?.substring(0, 100)}...`);
    }

    context.log(`Timer function executed at: ${new Date().toISOString()}`);
    context.log(`Using cached data of length: ${CACHED_BLOB_DATA?.length || 0}`);
};

Esempio: Trigger HTTP con uscita in coda

Questa funzione si attiva su una richiesta HTTP, scrive un messaggio in una coda di archiviazione e restituisce una risposta HTTP.

const { app, output } = require('@azure/functions');

const queueOutput = output.storageQueue({
    connection: 'AzureWebJobsStorage',
    queueName: 'myqueue'
});

app.http('httpTriggerWithQueue', {
    methods: ['GET', 'POST'],
    extraOutputs: [queueOutput],
    handler: async (request, context) => {
        const name = request.query.get('name') || 'World';
        const message = {
            id: context.invocationId,
            name: name,
            timestamp: new Date().toISOString()
        };

        // Write to queue output
        context.extraOutputs.set(queueOutput, JSON.stringify(message));
        context.log(`Message sent to queue: ${JSON.stringify(message)}`);

        return {
            body: `Hello, ${name}! Message queued successfully.`
        };
    }
});

Questa funzione si attiva su una richiesta HTTP, scrive un messaggio in una coda di archiviazione e restituisce una risposta HTTP.

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "outputQueue",
      "queueName": "myqueue",
      "connection": "AzureWebJobsStorage"
    }
  ]
}
module.exports = async function (context, req) {
    const name = (req.query.name || (req.body && req.body.name)) || 'World';
    const message = {
        id: context.invocationId,
        name: name,
        timestamp: new Date().toISOString()
    };

    // Write to queue output
    context.bindings.outputQueue = JSON.stringify(message);
    context.log(`Message sent to queue: ${JSON.stringify(message)}`);

    return {
        status: 200,
        body: `Hello, ${name}! Message queued successfully.`
    };
};

Gli oggetti app, trigger, input e output esportati dal modulo @azure/functions forniscono metodi specifici del tipo per la maggior parte dei tipi. Per tutti i tipi non supportati, viene fornito un metodo generic per consentire di specificare manualmente la configurazione. Il metodo generic 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!` };
  },
});

::: zona di fondo

Contesto di chiamata

Ogni invocazione della tua funzione riceve un oggetto di invocazione context. Usa questo oggetto per leggere input, impostare output, scrivere nei log e accedere a vari metadati. Nel modello v3, passi sempre l'oggetto di contesto come primo argomento al tuo gestore.

L'oggetto context include le seguenti proprietà:

Proprietà Descrizione
invocationId L'ID della chiamata di funzione corrente.
executionContext Vedere il contesto di esecuzione.
bindings Vedere le associazioni.
bindingData Metadati relativi all'input del trigger per questa invocazione, escludendo il valore stesso. Ad esempio, un trigger dell'hub eventi ha una proprietà enqueuedTimeUtc.
traceContext Contesto per la traccia distribuita. Per altre informazioni, vedere Trace Context.
bindingDefinitions La configurazione degli input e degli output, come definito in function.json.
req Vedere richiesta HTTP.
res Vedere risposta HTTP.

context.executionContext

L'oggetto context.executionContext ha le proprietà seguenti:

Proprietà Descrizione
invocationId L'ID della chiamata di funzione corrente.
functionName Il nome della funzione che stai invocando. Il nome della cartella contenente il file function.json determina il nome della funzione.
functionDirectory Cartella contenente il file function.json.
retryContext Vedere il contesto di ripetizione dei tentativi.

context.executionContext.retryContext

L'oggetto context.executionContext.retryContext ha le proprietà seguenti:

Proprietà Descrizione
retryCount Numero che rappresenta il tentativo di ripetizione corrente.
maxRetryCount Numero massimo di tentativi di esecuzione. Un valore di -1 indica di riprovare per un periodo illimitato.
exception Eccezione che ha causato il nuovo tentativo.

context.bindings

Usa l'oggetto context.bindings per leggere input o impostare output. L'esempio seguente è un trigger della coda di archiviazione che usa context.bindings per copiare un blob di archiviazione di input in un blob di archiviazione di output. 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 metodo context.done è deprecato. Prima che Funzioni di Azure supportasse funzioni asincrone, segnalavi che la tua funzione era stata eseguita chiamando context.done():

module.exports = function (context, request) {
  context.log("this pattern is now deprecated");
  context.done();
};

Rimuovere la chiamata a context.done(). Segna la tua funzione come asincrona così che restituisca una promessa (anche se non await hai 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 invocazione della tua funzione riceve un context oggetto di invocazione. Questo oggetto contiene informazioni sulla tua invocazione e sui metodi di registrazione. Nel modello v4, di solito si passa l'oggetto context come secondo argomento al tuo handler.

La InvocationContext classe include le proprietà seguenti:

Proprietà Descrizione
invocationId L'ID della chiamata di 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 il contesto di ripetizione dei tentativi.
traceContext Contesto per la traccia distribuita. Per altre 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 proprietà enqueuedTimeUtc.
options Le opzioni utilizzate durante la registrazione della funzione, dopo che sono state validate e i valori predefiniti, sono esplicitamente specificate.

Contesto di ripetizione dei tentativi

L'oggetto retryContext ha le proprietà seguenti:

Proprietà Descrizione
retryCount Numero che rappresenta il tentativo di ripetizione corrente.
maxRetryCount Numero massimo di tentativi di esecuzione. Un valore di -1 indica di riprovare per un periodo illimitato.
exception Eccezione che ha causato il nuovo tentativo.

Per altre informazioni, vedere retry-policies.

Registrazione

In Funzioni di Azure, usa context.log() per scrivere i log. Funzioni di Azure si integra con applicazione Azure 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.

Note

Se usi il metodo alternativo Node.js console.log , i log a livello di app vengono tracciati ma non associati a una funzione specifica. Usa context per la registrazione invece che console per far sì 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 , si usano i seguenti metodi per 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

Functions ti permette di definire il livello di soglia per tracciare e visualizzare i log. Per impostare la soglia, utilizzare la proprietà logging.logLevel nel file host.json. Questa proprietà ti permette di definire un livello predefinito per 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 maggiore controllo, usa l'SDK di Application Insights Node.js per inviare log, metriche e dipendenze personalizzate alla tua istanza di Application Insight.

Note

I metodi in Application Insights Node.js SDK possono cambiare nel tempo. Potrebbero esserci piccole differenze di sintassi rispetto agli esempi illustrati di seguito. Per gli esempi di utilizzo più recenti dell'API, vedere la documentazione di Application Insights Node.js SDK.

Per il tracciamento distribuito nel modello di programmazione Node.js v4, usa il @azure/functions-opentelemetry-instrumentation pacchetto invece dell'SDK Application Insights. Questo pacchetto fornisce la strumentazione automatica basata su OpenTelemetry per Funzioni di Azure. Per altre informazioni, vedere il repository OpenTelemetry Funzioni di Azure Instrumentation for Node.js GitHub.

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 ti permette di correlare tutti i log generati automaticamente e personalizzati per una determinata invocazione 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 oggetti HttpRequest e HttpResponse per rappresentare i messaggi HTTP. Le classi rappresentano un subset del recupero standard, usando il pacchetto undici di Node.js.

Richiesta HTTP

Accedi 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}"`);
    

  • Dalla proprietà context.req:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    

  • Dai binding di input nominati: Questa opzione funziona come qualsiasi binding non HTTP. Il nome dell'associazione in function.json deve corrispondere alla chiave in context.bindingso "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}"`);
    

L'oggetto HttpRequest ha le proprietà seguenti:

Proprietà TIPO Descrizione
method string Metodo di richiesta HTTP usato per richiamare questa funzione.
url string URL richiesta.
headers Record<string, string> Intestazioni di richiesta HTTP. Questo oggetto fa distinzione tra maiuscole e minuscole. Usa invece request.getHeader('header-name'), che non fa 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.

Puoi accedere alla richiesta come primo argomento per il tuo handler per una funzione attivata da HTTP.

async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

L'oggetto HttpRequest ha le proprietà seguenti:

Proprietà TIPO Descrizione
method string Metodo di richiesta HTTP usato per richiamare questa funzione.
url string URL 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 risposta, utilizzare i seguenti metodi:

Metodo Tipo restituito
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

Note

Puoi eseguire le funzioni corporee solo una volta. Le chiamate successive si risolvono con stringhe vuote o ArrayBuffer.

Risposta HTTP

Puoi impostare la risposta in diversi modi. Ad esempio, è possibile usare:

  • Impostare la proprietà context.res:

    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    

  • Restituire la risposta: se la funzione è asincrona e si imposta il nome dell'associazione su $return in function.json, è possibile restituire la risposta direttamente anziché impostarla su context.

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    

  • Imposta il binding di output denominato: Questa opzione funziona allo stesso modo di qualsiasi altro binding non HTTP. Il nome dell'associazione in function.json deve corrispondere alla chiave in context.bindingso "response1" nell'esempio seguente:

    {
      "type": "http",
      "direction": "out",
      "name": "response1"
    }
    
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    

  • Chiamare context.res.send(): questa opzione è deprecata. Chiama context.done() implicitamente e non puoi usarlo 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à TIPO 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 context.res predefinito usa l'interfaccia HttpResponseFull, che supporta i metodi seguenti oltre alle proprietà HttpResponseSimple:

Metodo Descrizione
status() Imposta lo stato.
setHeader() Imposta un campo di intestazione. NOTA:res.set() e res.header() sono anche supportati e fanno la stessa cosa.
getHeader() Riceve un campo di testa. NOTA:res.get() è anche supportata e fa la stessa cosa.
removeHeader() Rimuove un'intestazione.
type() Imposta l'intestazione "content-type".
send() Questo metodo è deprecato. Imposta il corpo e chiama context.done() per indicare che una funzione di sincronizzazione è stata completata. NOTA:res.end() è anche supportata e fa la stessa cosa.
sendStatus() Questo metodo è deprecato. Imposta il codice di stato e chiama 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 è terminata.

Puoi impostare la risposta in diversi modi. Ad esempio, è possibile usare:

  • Un'interfaccia semplice con tipo HttpResponseInit: Questa opzione è il modo più conciso per restituire le risposte.

    return { body: `Hello, world!` };
    

L'interfaccia HttpResponseInit ha le proprietà seguenti:

Proprietà TIPO Descrizione
body BodyInit (facoltativo) Corpo della risposta HTTP come uno dei ArrayBuffer, AsyncIterable<Uint8Array>, Blob, FormData, Iterable<Uint8Array>, NodeJS.ArrayBufferView, URLSearchParams, null o string.
jsonBody any (facoltativo) Corpo della risposta HTTP serializzabile in JSON. Se impostata, la proprietà HttpResponseInit.body 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 classe HttpResponse accetta un HttpResponseInit facoltativo come argomento per il relativo costruttore e ha le proprietà seguenti:

Proprietà TIPO 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à 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 HttpRequest e HttpResponse esistenti nel modello di programmazione v4 supportano già vari modi per gestire il corpo del messaggio, tra cui come flusso.

Prerequisiti

Abilitare i flussi

Usare questi passaggi per abilitare i flussi HTTP nell'app per le funzioni in Azure e nei progetti locali:

  1. Se si prevede di trasmettere grandi quantità di dati, modificare l'impostazione FUNCTIONS_REQUEST_BODY_SIZE_LIMIT in Azure. La dimensione massima consentita di default è 104857600, che limita le tue richieste a circa 100 MB.

  2. Per lo sviluppo locale, aggiungere anche FUNCTIONS_REQUEST_BODY_SIZE_LIMIT al file local.settings.json.

  3. Aggiungere il codice seguente all'app in qualsiasi file incluso nel campo principale.

    const { app } = require("@azure/functions");
    
    app.setup({ enableHttpStream: true });
    

Esempi di flusso

L'esempio seguente mostra una funzione attivata da HTTP che riceve dati tramite una richiesta HTTP POST. La funzione trasmette questi dati in 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!' };
    },
});

Il seguente esempio mostra una funzione attivata da HTTP che trasmette il contenuto di un file come risposta alle richieste HTTP GET in arrivo:

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 a usare che utilizza stream, dai un'occhiata a questo esempio su GitHub.

Considerazioni sul flusso

  • Usalo request.body per ottenere il massimo beneficio dall'uso degli stream. Puoi comunque usare metodi come request.text(), che restituiscono sempre il corpo come una stringa.

Hook

Il modello v3 non supporta i ganci. 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. L'ordine in cui registri i hook determina l'ordine in cui vengono eseguiti. Puoi registrare hook da qualsiasi file nella tua app. Esistono due livelli di hook: a livello di app e a livello di invocazione.

Hook di chiamata

Gli hook di invocazione si attivano una volta per ogni invocazione della tua funzione. Un preInvocation hook corre prima che la funzione venga eseguita, e un postInvocation hook dopo che la funzione venga eseguita. Di default, il tuo hook viene eseguito per tutti i tipi di trigger, ma puoi anche filtrare per tipo. L'esempio seguente illustra come registrare un hook di chiamata e filtrare in base al tipo di trigger:

const { app } = require('@azure/functions');

// Pre-invocation hook with trigger filtering
app.hook.preInvocation('httpPreInvocation', async (context) => {
  context.hookData.startTime = Date.now();
  context.invocationContext.log(`Pre-invocation hook executed for ${context.invocationContext.functionName}`);

  // Add custom headers or modify function handler if needed
  if (context.functionHandler.name === 'httpTrigger') {
    context.invocationContext.log('HTTP function detected, preparing request processing');
  }
}, {
  filter: ['httpTrigger']
});

// Post-invocation hook
app.hook.postInvocation('httpPostInvocation', async (context) => {
  const duration = Date.now() - context.hookData.startTime;
  context.invocationContext.log(`Function ${context.invocationContext.functionName} completed in ${duration}ms`);

  // Log results or errors
  if (context.error) {
    context.invocationContext.log.error(`Function failed: ${context.error.message}`);
  } else {
    context.invocationContext.log(`Function succeeded with result: ${JSON.stringify(context.result)}`);
  }
}, {
  filter: ['httpTrigger']
});

Il primo argomento del gestore hook è un oggetto di contesto specifico di tale tipo di hook.

L'oggetto PreInvocationContext ha le proprietà seguenti:

Proprietà Descrizione
inputs Gli argomenti li trasmetti all'invocazione.
functionHandler Gestore della funzione per la chiamata. Le modifiche apportate a questo valore influiscono sulla funzione stessa.
invocationContext L’oggetto contesto di chiamata passato alla funzione.
hookData Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. Usa un nome di proprietà unico in modo che non entri in conflitto con i dati di altri hook.

L'oggetto PostInvocationContext ha le proprietà seguenti:

Proprietà Descrizione
inputs Gli argomenti li trasmetti all'invocazione.
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 L’oggetto contesto di chiamata passato alla funzione.
hookData Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. Usa un nome di proprietà unico in modo che non entri in conflitto con i dati di altri hook.

Hook dell'app

Il runtime esegue gli hook dell'app una sola volta per ciascuna istanza della tua app. Esegue gli hook appStart durante l'avvio e gli hook appTerminate durante l'arresto. Gli hook di terminazione dell'app hanno un tempo limitato per l'esecuzione e non vengono eseguiti in tutti gli scenari.

Il runtime di Funzioni di Azure attualmente non supporta la registrazione del contesto al di fuori di un'invocazione. 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');
const appInsights = require('applicationinsights');

// Initialize Application Insights for app-level logging
appInsights.setup().start();
const client = appInsights.defaultClient;

// App start hook
app.hook.appStart('appStartup', async (context) => {
  context.hookData.appStartTime = Date.now();
  context.hookData.initializationData = {};

  // Initialize shared resources, database connections, etc.
  client.trackEvent({
    name: 'FunctionAppStarted',
    properties: {
      timestamp: new Date().toISOString(),
      nodeVersion: process.version
    }
  });

  // Set up global configurations
  process.env.APP_INITIALIZED = 'true';
});

// App terminate hook
app.hook.appTerminate('appShutdown', async (context) => {
  const uptime = Date.now() - context.hookData.appStartTime;

  // Cleanup resources, close connections, etc.
  client.trackEvent({
    name: 'FunctionAppTerminated',
    properties: {
      uptime: uptime,
      timestamp: new Date().toISOString()
    }
  });

  // Flush Application Insights data
  await new Promise((resolve) => client.flush({ callback: resolve }));
});

Il primo argomento del gestore hook è un oggetto di contesto specifico di tale tipo di hook.

L'oggetto AppStartContext possiede la seguente proprietà:

Proprietà Descrizione
hookData Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. Usa un nome di proprietà unico in modo che non entri in conflitto con i dati di altri hook.

L'oggetto AppTerminateContext possiede la seguente proprietà:

Proprietà Descrizione
hookData Posizione consigliata per archiviare e condividere dati tra hook nello stesso ambito. Usa un nome di proprietà unico in modo che non entri in conflitto con i dati di altri hook.

Migliori pratiche per gli hook

Quando utilizzi gli hook nelle tue Funzioni di Azure, considera queste best practice:

Considerazioni sulle prestazioni

  • Mantenere il tempo di esecuzione del hook al minimo per evitare di compromettere le prestazioni della funzione.
  • Utilizzare operazioni asincrone dove possibile per prevenire blocchi.
  • Considera il sovraccarico degli hook quando elabori richieste ad alto volume.

Gestione degli errori

  • Includi sempre una corretta gestione degli errori nei tuoi hook.
  • Non lasciare che i guasti al gancio causino guasti funzionali a meno che non sia assolutamente necessario.
  • Registra gli errori degli hook in modo appropriato per il debug.

Condivisione dei dati

  • Usalo hookData per condividere informazioni tra gli hook pre e post invocazione.
  • Usa nomi di proprietà unici per evitare conflitti con altri agganci.
  • Pulire i dati dei hook quando non sono più necessari per prevenire perdite di memoria.

Filtro

  • Usa il filtraggio del tipo trigger per assicurarti che i hook vengano eseguiti solo per le funzioni rilevanti.
  • Sii specifico con i tuoi filtri per ottimizzare le prestazioni.

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 utilizza soglie integrate (non configurabili dall'utente) per diversi tipi di trigger per decidere quando aggiungere istanze, come l'età dei messaggi e la dimensione 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 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 usi questa impostazione, eseguire da un file package può compensare questi svantaggi.

Versione del nodo

È possibile visualizzare la versione corrente usata dal runtime registrando process.version da qualsiasi funzione. Per un elenco delle versioni di Node.js supportate da ogni modello di programmazione, vedere supported versions.

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.

Quando viene eseguito su Windows, imposta la versione di Node.js usando l'impostazione dell'applicazione WEBSITE_NODE_DEFAULT_VERSION. Aggiorna questa impostazione utilizzando la interfaccia della riga di comando di Azure o tramite il portale 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, consultare Migrazione delle app da Funzioni di Azure versione 3.x alla versione 4.x.

Eseguire il comando 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=~22 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>

Questo comando imposta l'impostazione dell'applicazioneWEBSITE_NODE_DEFAULT_VERSION alla versione ~22LTS supportata.

Dopo aver fatto modifiche, la tua app di funzione si riavvia. Per altre informazioni sul supporto delle funzioni per Node.js, vedere Language Runtime support policy.

Variabili di ambiente

Usa variabili di ambiente per gestire segreti operativi, come stringhe di connessione, chiavi ed endpoint. Usali anche per configurazioni di ambiente, come le variabili di profilo. Aggiungi variabili di ambiente sia nel tuo ambiente locale che cloud, e accedi a esse tramite process.env il codice della tua funzione.

L'esempio seguente registra la variabile di ambiente WEBSITE_SITE_NAME:

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 file local.settings.json, in cui le variabili di ambiente vengono archiviate nell'oggetto Values.

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CUSTOM_ENV_VAR_1": "hello",
    "CUSTOM_ENV_VAR_2": "world"
  }
}

Nell'ambiente cloud Azure

Quando si esegue in Azure, l'app per le funzioni consente di impostare e usare Impostazioni di applicazione, ad esempio le stringhe 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:

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

Node.js ha diverse variabili di ambiente Funzioni specifiche per essa:

languageWorkers__node__arguments

Usa questa impostazione per specificare argomentazioni personalizzate quando inizi il tuo processo Node.js. Più spesso, lo usi localmente per avviare il worker in modalità debug, ma puoi anche usarlo in Azure se hai bisogno di argomentazioni personalizzate.

Avviso

Se possibile, evita di usare languageWorkers__node__arguments in Azure perché può influire negativamente sui tempi di avvio a freddo. Anziché usare worker pre-riscaldati, il runtime deve avviare un nuovo worker da zero utilizzando gli argomenti personalizzati specificati.

registrazionelogLevelWorker

Usa questa impostazione per modificare il livello di log predefinito dei log dei worker 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)

Note

I moduli ECMAScript sono attualmente una funzione di anteprima in Node.js 14 o superiori in Funzioni di Azure.

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 superiori, puoi scegliere di scrivere le tue 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 libreria uuid 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

Usa le function.json proprietà scriptFile e entryPoint imposta la posizione e il nome della funzione esportata. Quando utilizzi TypeScript, è necessaria la proprietà scriptFile e dovrebbe puntare al file JavaScript compilato.

Utilizzo di scriptFile

Di default, una funzione JavaScript viene eseguita da index.js. Questo file si trova nella stessa directory padre del corrispondente file function.json.

Usalo scriptFile per organizzare la struttura delle cartelle. Il seguente esempio mostra un modo per configurare le cartelle:

<project_root>/
 | - node_modules/
 | - myFirstFunction/
 | | - function.json
 | - lib/
 | | - sayHello.js
 | - host.json
 | - package.json

Il function.json file for myFirstFunction dovrebbe includere una scriptFile proprietà che punti al file con la funzione esportata da eseguire.

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

Utilizzo di entryPoint

Nel modello v3, devi esportare una funzione usando module.exports così che la funzione possa essere trovata ed eseguita. Di default, la funzione che viene eseguita quando viene attivata è l'unica esportazione da quel file. Può anche essere l'esportazione denominata run o l'esportazione denominata index. L'esempio seguente imposta entryPoint in function.json su un valore personalizzato, "logHello":

{
  "entryPoint": "logHello",
  "bindings": [
    ...
  ]
}
async function logHello(context) {
  context.log("Hello, world!");
}

module.exports = { logHello };

Consigli

Questa sezione descrive diversi modelli di impatto per Node.js app che dovresti seguire.

Scegliere i piani di servizio app con una singola vCPU

Quando crei un'app di funzioni che utilizza il piano App Service, seleziona un piano a singolo vCPU invece di un piano con più vCPU. Oggi, Functions esegue Node.js funzioni in modo più efficiente su VM a singolo vCPU, e l'uso di VM più grandi non porta i miglioramenti di prestazioni attesi. Quando necessario, puoi scalare aggiungendo più istanze VM a singolo vCPU, oppure puoi abilitare l'autoscala. 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à. Avvio a freddo fa riferimento alla prima volta che l'app per le funzioni inizia dopo un periodo di inattività, richiedendo più tempo per l'avvio. Per app Node.js 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. Molte modalità di distribuzione usano questo modello per impostazione predefinita, ma se riscontri tempi elevati di avvio a freddo, verifica di usare questa modalità.

Usare async ed await

Quando scrivi funzioni di Azure in Node.js, scrivi il codice usando le parole chiave async e await. Scrivere codice usando async e await invece di callback o .then e .catch con Promises ti aiuta a evitare due problemi comuni:

  • Generazione di eccezioni non rilevate che arrestano in modo anomalo il processo di Node.js, che potenzialmente influisce 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 asincrono fs.readFile 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). Restituire senza assicurarsi che il callback si concluda significa che la risposta HTTP a volte ha 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 asincrono fs.readFile viene richiamato con una funzione di callback error-first come secondo parametro. Questo codice causa entrambi i problemi menzionati in precedenza. Un'eccezione che non è esplicitamente rilevata nell'ambito corretto può far crashare l'intero processo (problema #1). Chiamare il metodo obsoleto context.done() al di fuori dell'ambito del callback può segnalare che la funzione è terminata prima che il file venga letto (problema #2). In questo esempio, chiamare context.done() troppo presto genera voci di log mancanti a partire da 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();
};

Usa le async parole chiave e await per evitare entrambi questi problemi. La maggior parte delle API nell'ecosistema Node.js ora supporta promesse in qualche forma. 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 parola chiave await indica che i passaggi seguenti readFile vengono 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;
        }
    },
});

Quando usi 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}`);
};

Risolvere problemi

Vedere la guida alla risoluzione dei problemi Node.js.

Passaggi successivi

Per altre informazioni, vedere le seguenti risorse: