Azure Functions Node.js-Entwicklerreferenz

Dieser Leitfaden ist eine Einführung in die Entwicklung von Azure Functions mithilfe von JavaScript oder TypeScript. Der Artikel setzt voraus, dass Sie den Azure Functions Entwicklerleitfaden bereits gelesen haben.

Wichtig

Der Inhalt dieses Artikels ändert sich basierend auf der Wahl des Node.js-Programmiermodells in der Auswahl oben auf dieser Seite. Die ausgewählte Version sollte mit der Version des @azure/functions-npm-Pakets übereinstimmen, die Sie in Ihrer App verwenden. Wenn dieses Paket nicht in Ihrer Datei package.json aufgeführt wird, ist die Standardversion v3. Weitere Informationen zu den Unterschieden zwischen v3 und v4 finden Sie im Migrationshandbuch.

Für Node.js-Entwickler sind möglicherweise auch folgende Artikel interessant:

Erste Schritte Konzepte Geführte Tutorials

Überlegungen

  • Das Node.js-Programmiermodell sollte nicht mit der Azure Functions-Runtime verwechselt werden:
    • Programmiermodell: Definiert, wie Sie Ihren Code erstellen und ist spezifisch für JavaScript und TypeScript.
    • Runtime: Definiert das zugrunde liegende Verhalten von Azure Functions und wird für alle Sprachen gemeinsam verwendet.
  • Die Programmiermodellversion ist eng an die Version des @azure/functions-npm-Pakets gebunden. Sie wird unabhängig von der Runtime mit Versionsangaben versehen. Sowohl die Runtime als auch das Programmiermodell verwenden die Angabe „4“ als neueste Hauptversion, aber das ist Zufall.
  • Sie können die v3- und v4-Programmiermodelle nicht in derselben Funktions-App kombinieren. Sobald Sie eine v4-Funktion in Ihrer App registrieren, werden alle in function.json-Dateien registrierten v3-Funktionen ignoriert.

Unterstützte Versionen

Die folgende Tabelle zeigt jede Version des Node.js-Programmiermodells zusammen mit den unterstützten Versionen der Azure Functions-Runtime und von Node.js.

Programmiermodellversion Supportebene Version der Functions-Laufzeit Node.js-Version Beschreibung
4.x Allgemein verfügbar 4.25+ 20.x, 18.x Unterstützt eine flexible Dateistruktur und einen codeorientierten Ansatz für Trigger und Bindungen.
3.x Allgemein verfügbar 4.x 20.x, 18.x, 16.x, 14.x Erfordert eine bestimmte Dateistruktur mit Ihren Triggern und Bindungen, die in einer Datei „function.json“ deklariert werden.
2.x 3.x 14.x, 12.x, 10.x Hat das Ende der Unterstützung am 13. Dezember 2022 erreicht. Weitere Informationen finden Sie unter Functions-Versionen.
1.x 2.x 10.x, 8.x Hat das Ende der Unterstützung am 13. Dezember 2022 erreicht. Weitere Informationen finden Sie unter Functions-Versionen.

Ordnerstruktur

Die erforderlichen Ordnerstruktur für ein JavaScript-Projekt sieht folgendermaßen aus:

<project_root>/
 | - .vscode/
 | - node_modules/
 | - myFirstFunction/
 | | - index.js
 | | - function.json
 | - mySecondFunction/
 | | - index.js
 | | - function.json
 | - .funcignore
 | - host.json
 | - local.settings.json
 | - package.json

Der Hauptprojektordner (<project_root>) kann die folgenden Dateien enthalten:

  • .vscode/: (optional) Diese Datei enthält die gespeicherten Visual Studio Code-Konfigurationen. Weitere Informationen finden Sie unter Visual Studio Code-Einstellungen.
  • myFirstFunction/function.json: Enthält die Konfiguration für den Trigger, die Eingaben und Ausgaben der Funktion. Der Name des Verzeichnisses bestimmt den Namen Ihrer Funktion.
  • myFirstFunction/index.js: Speichert Ihren Funktionscode. Wie Sie diesen Standard-Dateipfad ändern, erfahren Sie unter Verwendung von scriptFile.
  • .funcignore: (optional) In dieser Datei werden Dateien deklariert, die nicht in Azure veröffentlicht werden sollen. Normalerweise enthält diese Datei .vscode/, um die Editor-Einstellung zu ignorieren, tests/, um Testfälle zu ignorieren, und local.settings.json, um zu verhindern, dass lokale App-Einstellungen veröffentlicht werden.
  • host.json: Enthält Konfigurationsoptionen, die sich auf alle Funktionen in einer Funktions-App-Instanz auswirken. Diese Datei wird in Azure veröffentlicht. Nicht alle Optionen werden bei lokaler Ausführung unterstützt. Weitere Informationen finden Sie unter host.json.
  • local.settings.json: Wird verwendet, um bei lokaler Ausführung App-Einstellungen und Verbindungszeichenfolgen zu speichern. Diese Datei wird nicht in Azure veröffentlicht. Weitere Informationen finden Sie unter local.settings.file.
  • package.json: Enthält Konfigurationsoptionen, z. B. eine Liste von Paketabhängigkeiten, den Haupteinstiegspunkt sowie Skripts.

Die empfohlene Ordnerstruktur für ein JavaScript-Projekt sieht wie im folgenden Beispiel aus:

<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

Der Hauptprojektordner (<project_root>) kann die folgenden Dateien enthalten:

  • .vscode/: (optional) Diese Datei enthält die gespeicherten Visual Studio Code-Konfigurationen. Weitere Informationen finden Sie unter Visual Studio Code-Einstellungen.
  • src/functions: Der Standardspeicherort für alle Funktionen und die zugehörigen Trigger und Bindungen.
  • test/: Enthält die Testfälle ihrer Funktions-App.
  • .funcignore: (optional) In dieser Datei werden Dateien deklariert, die nicht in Azure veröffentlicht werden sollen. Normalerweise enthält diese Datei .vscode/, um die Editor-Einstellung zu ignorieren, tests/, um Testfälle zu ignorieren, und local.settings.json, um zu verhindern, dass lokale App-Einstellungen veröffentlicht werden.
  • host.json: Enthält Konfigurationsoptionen, die sich auf alle Funktionen in einer Funktions-App-Instanz auswirken. Diese Datei wird in Azure veröffentlicht. Nicht alle Optionen werden bei lokaler Ausführung unterstützt. Weitere Informationen finden Sie unter host.json.
  • local.settings.json: Wird verwendet, um bei lokaler Ausführung App-Einstellungen und Verbindungszeichenfolgen zu speichern. Diese Datei wird nicht in Azure veröffentlicht. Weitere Informationen finden Sie unter local.settings.file.
  • package.json: Enthält Konfigurationsoptionen, z. B. eine Liste von Paketabhängigkeiten, den Haupteinstiegspunkt sowie Skripts.

Registrieren einer Funktion

Das v3-Modell registriert eine Funktion basierend auf dem Vorhandensein von zwei Dateien. Zunächst benötigen Sie eine function.json-Datei, die sich in einem Ordner eine Ebene unterhalb des Stammverzeichnisses Ihrer Anwendung befindet. Außerdem benötigen Sie eine JavaScript-Datei, die Ihre Funktion exportiert. Standardmäßig sucht das Modell nach einer index.js-Datei, die sich im selben Ordner wie Ihr function.json befindet. Wenn Sie TypeScript verwenden, müssen Sie die Eigenschaft scriptFile in function.json verwenden, um auf die kompilierte JavaScript-Datei zu verweisen. Wie Sie den Dateispeicherort oder den Exportnamen Ihrer Funktion anpassen können, erfahren Sie unter Konfigurieren des Einstiegspunkts Ihrer Funktion.

Die Funktion, die Sie exportieren, sollte im v3-Modell immer als async function deklariert werden. Sie können auch eine synchrone Funktion exportieren. Dann müssen Sie jedoch context.done() aufrufen, um zu signalisieren, dass Ihre Funktion abgeschlossen ist. Dies ist veraltet und wird nicht empfohlen.

Ihrer Funktion wird ein Aufruf context als erstes Argument und Ihre Eingaben als die übrigen Argumente übergeben.

Das folgende Beispiel zeigt eine einfache Funktion, die ihre Auslösung protokolliert und dann mit Hello, world! antwortet:

{
  "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!' };
};

Das Programmiermodell lädt Ihre Funktionen basierend auf dem main-Feld in Ihrer Datei package.json. Sie können das main-Feld auf eine einzelne Datei oder mithilfe eines Globmusters auf mehrere Dateien festlegen. Die folgende Tabelle enthält Beispielwerte für das Feld main:

Beispiel BESCHREIBUNG
src/index.js Registrieren Sie Funktionen in einer einzelnen Stammdatei.
src/functions/*.js Registrieren Sie jede Funktion in ihrer eigenen Datei.
src/{index.js,functions/*.js} Eine Kombination, in der Sie jede Funktion in ihrer eigenen Datei registrieren, aber dennoch über eine Stammdatei für allgemeinen Code auf App-Ebene verfügen.

Um eine Funktion zu registrieren, müssen Sie das app-Objekt aus dem @azure/functions-npm-Modul importieren und die für Ihren Triggertyp spezifische Methode aufrufen. Das erste Argument beim Registrieren einer Funktion ist der Funktionsname. Das zweite Argument ist ein options-Objekt, das die Konfiguration für Ihren Trigger, Ihren Handler und alle anderen Eingaben oder Ausgaben angibt. In einigen Fällen, in denen die Triggerkonfiguration nicht erforderlich ist, können Sie den Handler direkt als zweites Argument anstelle eines options-Objekts übergeben.

Die Registrierung einer Funktion kann aus einer beliebigen Datei in Ihrem Projekt erfolgen, solange diese Datei (direkt oder indirekt) basierend auf dem main-Feld in Ihrer Datei package.json geladen wird. Die Funktion sollte in einem globalen Bereich registriert werden, da Sie Funktionen nach dem Starten von Ausführungen nicht mehr registrieren können.

Das folgende Beispiel zeigt eine einfache Funktion, die ihre Auslösung protokolliert und dann mit Hello, world! antwortet:

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!' };
    }
});

Eingaben und Ausgaben

Ihre Funktion muss über genau eine primäre Eingabe verfügen, die als Trigger bezeichnet wird. Sie kann auch sekundäre Ein- und/oder Ausgaben haben. Ein- und Ausgaben werden in Ihren function.json-Dateien konfiguriert und auch als Bindungen bezeichnet.

Eingaben

Eingaben sind Bindungen, für die direction auf in festgelegt ist. Der Hauptunterschied zwischen einem Trigger und einer sekundären Eingabe besteht darin, dass der type für einen Trigger auf Trigger endet, z. B. Typ blobTrigger im Vergleich zu Typ blob. Die meisten Funktionen verwenden nur einen Trigger. Es werden nicht viele sekundäre Eingabetypen unterstützt.

Auf Eingaben kann auf verschiedene Arten zugegriffen werden:

  • [Empfohlen] Als Argumente, die an Ihre Funktion übergeben werden: Verwenden Sie die Argumente in derselben Reihenfolge, wie sie in function.json definiert sind. Die Eigenschaft name, die in function.json definiert ist, muss nicht mit dem Namen Ihres Arguments übereinstimmen. Dies wird jedoch aus Gründen der Übersichtlichkeit empfohlen.

    module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
    
  • Als Eigenschaften von context.bindings: Verwenden Sie den Schlüssel, der der Eigenschaft name, die in function.jsondefiniert ist, entspricht.

    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);
    };
    

Ausgaben

Ausgaben sind Bindungen, für die direction auf out festgelegt ist. Dies kann auf verschiedene Arten geschehen:

  • [Empfohlen für einzelne Ausgabe] Direkte Rückgabe des Werts: Wenn Sie eine asynchrone Funktion verwenden, können Sie den Wert direkt zurückgeben. Sie müssen die Eigenschaft name der Ausgabebindung wie im folgenden Beispiel zu $return (in function.json) ändern:

    {
        "name": "$return",
        "type": "http",
        "direction": "out"
    }
    
    module.exports = async function (context, request) {
        return {
            body: "Hello, world!"
        };
    }
    
  • [Empfohlen für mehrere Ausgaben] Rückgabe eines Objekts, das alle Ausgaben enthält: Wenn Sie eine asynchrone Funktion verwenden, können Sie ein Objekt mit einer Eigenschaft zurückgeben, die dem Namen jeder Bindung in Ihrem function.json entspricht. Im folgenden Beispiel werden Ausgabebindungen mit den Namen „httpResponse“ und „queueOutput“ verwendet:

    {
        "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
        };
    };
    
  • Festlegen von Werten für context.bindings: Wenn Sie keine asynchrone Funktion verwenden oder die vorherigen Optionen nicht nutzen wollen, können Sie Werte, bei denen der Schlüssel mit dem Namen der Bindung übereinstimmt, direkt auf context.bindings festlegen. Im folgenden Beispiel werden Ausgabebindungen mit den Namen „httpResponse“ und „queueOutput“ verwendet:

    {
        "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;
    };
    

Datentyp für Bindungen

Sie können die Eigenschaft dataType für eine Eingabebindung verwenden, um den Typ Ihrer Eingabe zu ändern, es gibt jedoch ein paar Einschränkungen:

  • In Node.js werden nur string und binary unterstützt (nicht stream)
  • Bei HTTP-Eingaben wird die Eigenschaft dataType ignoriert. Verwenden Sie stattdessen Eigenschaften für das requestobjekt, um den Textkörper im gewünschten Format abzurufen. Weitere Informationen finden Sie unter HTTP-Anforderung.

Im folgenden Beispiel eines Speicherwarteschlangen-Triggers ist der Standardtyp von myQueueItem ein string, aber wenn Sie dataType auf binary setzen, ändert sich der Typ in einen 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');
    }
};

Ihre Funktion muss über genau eine primäre Eingabe verfügen, die als Trigger bezeichnet wird. Sie kann auch sekundäre Eingaben, eine primäre Ausgabe, die als Rückgabeausgabe bezeichnet wird, und/oder sekundäre Ausgaben enthalten. Inputs und Outputs werden auch außerhalb des Kontextes des Node.js-Programmiermodells als Bindungen bezeichnet. Vor v4 des Modells wurden diese Bindungen in function.json-Dateien konfiguriert.

Triggereingabe

Der Trigger ist die einzige erforderliche Eingabe oder Ausgabe. Für die meisten Triggertypen registrieren Sie eine Funktion mithilfe einer Methode für das app-Objekt, das nach dem Triggertyp benannt ist. Sie können für den Trigger spezifische Konfiguration direkt für das options-Argument angeben. Mit einem HTTP-Trigger können Sie beispielsweise eine Route angeben. Während der Ausführung wird der diesem Trigger entsprechende Wert als erstes Argument an Ihren Handler übergeben.

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

app.http('helloWorld1', {
    route: 'hello/world',
    handler: async (request, context) => {
        ...
    }
});

Zurückgegebene Ausgabe

Die Rückgabeausgabe ist optional und in einigen Fällen standardmäßig konfiguriert. Beispielsweise ist ein HTTP-Trigger, der mit app.http registriert ist, so konfiguriert, dass automatisch eine HTTP-Antwortausgabe zurückgegeben wird. Bei den meisten Ausgabetypen geben Sie die Rückgabekonfiguration für das options-Argument mithilfe des aus dem @azure/functions-Modul exportierten output-Objekts an. Während der Ausführung legen Sie diese Ausgabe fest, indem Sie sie von Ihrem Handler zurückgeben.

Im folgenden Beispiel werden ein Timer-Trigger und eine Speicherwarteschlangen-Ausgabe verwendet:

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

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.storageQueue({
        connection: 'storage_APPSETTING',
        ...
    }),
    handler: (myTimer, context) => {
        return { hello: 'world' }
    }
});

Zusätzliche Eingaben und Ausgaben

Zusätzlich zum Trigger und zur Rückgabe können Sie beim Registrieren einer Funktion weitere Eingaben oder Ausgaben für das options-Argument angeben. Die aus dem @azure/functions-Modul exportierten output- und input-Objekte stellen typspezifische Methoden bereit, um die Konfiguration zu erstellen. Während der Ausführung rufen Sie die Werte mit context.extraInputs.get oder context.extraOutputs.set ab bzw. legen sie fest, und übergeben das ursprüngliche Konfigurationsobjekt als erstes Argument.

Das folgende Beispiel ist eine Funktion, die von einer Speicherwarteschlange mit einer zusätzlichen Speicherblob-Eingabe ausgelöst wird, die in eine zusätzliche Speicherblob-Ausgabe kopiert wird. Die Warteschlangennachricht sollte der Name einer Datei sein und ersetzt {queueTrigger} als den zu kopierenden Blob-Namen, mit Hilfe eines Bindungsausdrucks.

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);
    }
});

Generische Eingaben und Ausgaben

Die vom @azure/functions-Modul exportierten app-, trigger-, input- und output-Objekte stellen typspezifische Methoden für die meisten Typen bereit. Für alle Typen, die nicht unterstützt werden, wird eine generic-Methode bereitgestellt, mit der Sie die Konfiguration manuell angeben können. Die generic-Methode kann auch verwendet werden, wenn Sie die Standardeinstellungen ändern möchten, die von einer typspezifischen Methode bereitgestellt werden.

Das folgende Beispiel ist eine einfache durch HTTP ausgelöste Funktion, die generische Methoden anstelle von typspezifischen Methoden verwendet.

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

Aufrufkontext

Bei jedem Aufruf Ihrer Funktion wird ein Aufruf-contextobjekt übergeben, das dazu dient, Eingaben zu lesen, Ausgaben festzulegen, in Protokolle zu schreiben und verschiedene Metadaten zu lesen. Im v3-Modell ist das Kontextobjekt immer das erste Argument, das an Ihren Handler übergeben wird.

Das context-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
invocationId Die ID des aktuellen Funktionsaufrufs.
executionContext Siehe Ausführungskontext.
bindings Siehe Bindungen.
bindingData Metadaten über die Triggereingabe für diesen Aufruf, ohne den Wert selbst. Beispielsweise verfügt ein Event Hub-Trigger über eine enqueuedTimeUtc-Eigenschaft.
traceContext Der Kontext für verteilte Ablaufverfolgung. Weitere Informationen finden Sie unter Trace Context.
bindingDefinitions Die Konfiguration Ihrer Ein- und Ausgaben, wie sie in function.jsondefiniert sind.
req Siehe HTTP-Anforderung.
res Siehe HTTP-Antwort.

context.executionContext

Das context.executionContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
invocationId Die ID des aktuellen Funktionsaufrufs.
functionName Der Name der Funktion, die aufgerufen wurde. Der Name des Ordners, der die Datei function.json enthält, bestimmt den Namen der Funktion.
functionDirectory Der Ordner, der die Datei function.json enthält.
retryContext Siehe Wiederholungskontext.

context.executionContext.retryContext

Das context.executionContext.retryContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft BESCHREIBUNG
retryCount Eine Zahl, die anzeigt, wie viele Wiederholungsversuche durchgeführt wurden.
maxRetryCount Maximale Anzahl von Wiederholungsversuchen für eine Ausführung. Der Wert -1 bedeutet unbegrenzte Wiederholungen.
exception Ausnahme, die den Wiederholungsversuch verursacht hat.

context.bindings

Das context.bindingsobjekt wird verwendet, um Eingaben zu lesen oder Ausgaben festzulegen. Das folgende Beispiel ist ein Speicherwarteschlangen-Trigger, der context.bindings verwendet, um eine Speicherblob-Eingabe in eine Speicherblob-Ausgabe zu kopieren. Der Inhalt der Warteschlangennachricht ersetzt {queueTrigger} als den zu kopierenden Dateinamen mit Hilfe eines Bindungsausdrucks.

{
    "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

Diese context.done-Methode ist veraltet. Bevor asynchrone Funktionen unterstützt wurden, signalisierte man durch den Aufruf von context.done(), dass die Funktion beendet ist:

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

Jetzt sollten Sie den Aufruf von context.done() entfernen und Ihre Funktion als asynchron markieren, damit sie ein Promise zurückgibt (auch wenn Sie nichts await). Sobald Ihre Funktion beendet ist (d.h. das zurückgegebene Promise aufgelöst ist), weiß das v3-Modell, dass Ihre Funktion beendet ist.

module.exports = async function (context, request) {
    context.log("you don't need context.done or an awaited call")
};

Bei jedem Aufruf Ihrer Funktion wird ein Aufruf-contextobjekt übergeben, das Informationen über Ihren Aufruf und die für die Protokollierung verwendeten Methoden enthält. Im v4-Modell ist das contextobjekt in der Regel das zweite Argument, das an Ihren Handler übergeben wird.

Die InvocationContext-Klasse weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
invocationId Die ID des aktuellen Funktionsaufrufs.
functionName Der Name der Funktion.
extraInputs Wird verwendet, um die Werte zusätzlicher Eingaben abzurufen. Weitere Informationen finden Sie unter Zusätzliche Eingaben und Ausgaben.
extraOutputs Wird verwendet, um die Werte zusätzlicher Ausgaben abzurufen. Weitere Informationen finden Sie unter Zusätzliche Eingaben und Ausgaben.
retryContext Siehe Wiederholungskontext.
traceContext Der Kontext für verteilte Ablaufverfolgung. Weitere Informationen finden Sie unter Trace Context.
triggerMetadata Metadaten über die Triggereingabe für diesen Aufruf, ohne den Wert selbst. Beispielsweise verfügt ein Event Hub-Trigger über eine enqueuedTimeUtc-Eigenschaft.
options Die Optionen, die beim Registrieren der Funktion verwendet werden, nachdem sie überprüft und die Standardwerte explizit angegeben wurden.

Wiederholungskontext

Das retryContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft BESCHREIBUNG
retryCount Eine Zahl, die anzeigt, wie viele Wiederholungsversuche durchgeführt wurden.
maxRetryCount Maximale Anzahl von Wiederholungsversuchen für eine Ausführung. Der Wert -1 bedeutet unbegrenzte Wiederholungen.
exception Ausnahme, die den Wiederholungsversuch verursacht hat.

Weitere Informationen finden Sie unter retry-policies.

Protokollierung

In Azure Functions wird empfohlen, context.log() zum Schreiben von Protokollen zu verwenden. Die Integration von Azure Functions und Azure Application Insights ermöglicht eine bessere Erfassung Ihrer Funktions-App-Protokolle. Application Insights ist eine Komponente von Azure Monitor und bietet Funktionen für die Erfassung, das visuelle Rendering und die Analyse von Anwendungsprotokollen sowie Ihrer Ausgaben der Ablaufverfolgung. Weitere Informationen finden Sie unter Überwachen von Azure Functions.

Hinweis

Wenn Sie die alternative Node.js-console.log-Methode verwenden, werden diese Protokolle auf App-Ebene nachverfolgt und nicht einer bestimmten Funktion zugeordnet. Es wird dringend empfohlen, context anstelle von console für die Protokollierung zu verwenden, damit alle Protokolle einer bestimmten Funktion zugeordnet sind.

Das folgende Beispiel schreibt ein Protokoll auf der Standardstufe „Information“, einschließlich der Aufruf-ID:

context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);

Protokollebenen

Neben der Standardmethode context.log gibt es folgende Methoden, mit denen Sie Protokolle auf bestimmten Ebenen schreiben können:

Methode BESCHREIBUNG
context.log.error() Schreibt ein Ereignis auf Fehlerebene in die Protokolle.
context.log.warn() Schreibt ein Ereignis auf Warnungsebene in die Protokolle.
context.log.info() Schreibt ein Ereignis auf Informationsebene in die Protokolle.
context.log.verbose() Schreibt ein Ereignis auf Ablaufverfolgungsebene in die Protokolle.
Methode BESCHREIBUNG
context.trace() Schreibt ein Ereignis auf Ablaufverfolgungsebene in die Protokolle.
context.debug() Schreibt ein Ereignis auf Debugebene in die Protokolle.
context.info() Schreibt ein Ereignis auf Informationsebene in die Protokolle.
context.warn() Schreibt ein Ereignis auf Warnungsebene in die Protokolle.
context.error() Schreibt ein Ereignis auf Fehlerebene in die Protokolle.

Protokollebene konfigurieren

Mit Azure Functions können Sie die Schwellenwertebene definieren, die beim Nachverfolgen und Anzeigen von Protokollen verwendet werden soll. Um den Schwellenwert festzulegen, verwenden Sie die Eigenschaft logging.logLevel in der Datei host.json. Mit dieser Eigenschaft können Sie eine Standardebene definieren, die auf alle Funktionen angewendet wird, oder einen Schwellenwert für jede einzelne Funktion. Weitere Informationen finden Sie unter Konfigurieren der Überwachung für Azure Functions.

Nachverfolgen benutzerdefinierter Daten

Ausgaben werden von Azure Functions standardmäßig als Ablaufverfolgungen in Application Insights geschrieben. Sollten Sie mehr Steuerungsmöglichkeiten benötigen, können Sie stattdessen das Application Insights Node.js SDK verwenden, um benutzerdefinierte Daten an Ihre Application Insights-Instanz zu senden.

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});
};

Mit dem Parameter tagOverrides wird die operation_Id auf die Aufrufkennung der Funktion festgelegt. Mithilfe dieser Einstellung können Sie die gesamten automatisch generierten und benutzerdefinierten Protokolle für einen bestimmten Funktionsaufruf korrelieren.

HTTP-Trigger

HTTP- und Webhook-Trigger verwenden Anforderungs- und Antwort-Objekte, um HTTP-Nachrichten darzustellen.

HTTP- und Webhook-Trigger verwenden HttpRequest- und HttpResponseobjekte zur Darstellung von HTTP-Nachrichten. Die Klassen stellen eine Teilmenge des Abrufstandards dar, wobei das undici-Paket von Node.js verwendet wird.

HTTP-Anforderung

Auf die Anforderung kann auf verschiedene Arten zugegriffen werden:

  • Als zweites Argument für Ihre Funktion:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${request.url}"`);
    
  • Über die context.req-Eigenschaft:

    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    
  • Aus den benannten Eingabebindungen: Diese Option funktioniert genauso wie jede nicht-HTTP-Bindung. Der Bindungsname in function.json muss mit dem Schlüssel auf context.bindings übereinstimmen oder im folgenden Beispiel „request1“ sein:

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

Das HttpRequest-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Typ BESCHREIBUNG
method string HTTP-Anforderungsmethode, die zum Aufrufen dieser Funktion verwendet wird.
url string Anforderungs-URL.
headers Record<string, string> HTTP-Anforderungsheader. Bei diesem Objekt wird die Groß-/Kleinschreibung beachtet. Es wird empfohlen, stattdessen request.getHeader('header-name') zu verwenden, wo die Groß-/Kleinschreibung nicht beachtet wird.
query Record<string, string> Schlüssel und Werte von Abfragezeichenfolgen-Parametern aus der URL.
params Record<string, string> Routenparameterschlüssel und -werte.
user HttpRequestUser | null Objekt, das den angemeldeten Benutzer darstellt, entweder über Functions-Authentifizierung, SWA-Authentifizierung oder NULL, wenn kein solcher Benutzer angemeldet ist.
body Buffer | string | any Wenn der Medientyp „application/octet-stream“ oder „multipart/*“ lautet, ist body ein Puffer. Wenn der Wert eine parsefähige JSON-Zeichenkette ist, ist body das geparste Objekt. Andernfalls ist body eine Zeichenfolge.
rawBody string Der Textkörper als Zeichenfolge. Trotz des Namens gibt diese Eigenschaft keinen Puffer zurück.
bufferBody Buffer Der Textkörper als Puffer.

Die Anforderung kann als erstes Argument für Ihren Handler für eine HTTP-ausgelöste Funktion verwendet werden.

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

Das HttpRequest-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Typ BESCHREIBUNG
method string HTTP-Anforderungsmethode, die zum Aufrufen dieser Funktion verwendet wird.
url string Anforderungs-URL.
headers Headers HTTP-Anforderungsheader.
query URLSearchParams Schlüssel und Werte von Abfragezeichenfolgen-Parametern aus der URL.
params Record<string, string> Routenparameterschlüssel und -werte.
user HttpRequestUser | null Objekt, das den angemeldeten Benutzer darstellt, entweder über Functions-Authentifizierung, SWA-Authentifizierung oder NULL, wenn kein solcher Benutzer angemeldet ist.
body ReadableStream | null Textkörper als lesbarer Stream.
bodyUsed boolean Ein boolescher Wert, der angibt, ob der Körper bereits gelesen wurde.

Um auf den Textkörper einer Anforderung oder Antwort zuzugreifen, können die folgenden Methoden verwendet werden:

Methode Rückgabetyp
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

Hinweis

Die Textkörperfunktionen können nur ein Mal ausgeführt werden. Nachfolgende Aufrufe werden mit leeren Zeichenfolgen/ArrayBuffers aufgelöst.

HTTP-Antwort

Die Antwort kann auf verschiedene Arten festgelegt werden:

  • Festlegen der Eigenschaft context.res:

    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    
  • Zurückgeben der Antwort: Wenn Ihre Funktion asynchron ist und Sie den Bindungsnamen auf $return festlegen (in Ihrer function.json), können Sie die Antwort direkt zurückgeben, anstatt sie auf contextfestzulegen.

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    
  • Festlegen der benannten Ausgabebindung: Diese Option funktioniert genauso wie jede nicht-HTTP-Bindung. Der Bindungsname in function.json muss mit dem Schlüssel auf context.bindings übereinstimmen oder im folgenden Beispiel „response1“ sein:

    {
        "type": "http",
        "direction": "out",
        "name": "response1"
    }
    
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    
  • Aufruf von context.res.send(): Diese Option ist veraltet. Es wird implizit context.done() aufgerufen und kann nicht in einer asynchronen Funktion verwendet werden.

    module.exports = function (context, request) {
        context.res.send(`Hello, world!`);
    

Wenn Sie beim Festlegen der Antwort ein neues Objekt erstellen, muss dieses Objekt mit der HttpResponseSimple-Schnittstelle übereinstimmen, die die folgenden Eigenschaften hat:

Eigenschaft Typ BESCHREIBUNG
headers Record<string, string> (optional) HTTP-Antwortheader.
cookies Cookie[] (optional) HTTP-Antwortcookies.
body any (optional) HTTP-Antworttext.
statusCode number (optional) HTTP-Antwortstatuscode. Wenn nicht festgelegt, ist der Standardwert 200.
status number (optional) Entspricht statusCode. Diese Eigenschaft wird ignoriert, wenn statusCode gesetzt ist.

Sie können das context.resobjekt auch ändern, ohne es zu überschreiben. Das Standardobjekt context.res verwendet die HttpResponseFull-Schnittstelle, die zusätzlich zu den HttpResponseSimple-Eigenschaften die folgenden Methoden unterstützt:

Methode BESCHREIBUNG
status() Legt den Status fest.
setHeader() Legt ein Headerfeld fest. HINWEIS: res.set() und res.header() werden ebenfalls unterstützt und tun dasselbe.
getHeader() Abrufen eines Headerfelds. HINWEIS: res.get() wird ebenfalls unterstützt und tut dasselbe.
removeHeader() Entfernt einen Header.
type() Legt den Header „content-type“ fest.
send() Diese Methode ist als veraltet markiert. Es legt den Textkörper fest und ruft context.done() auf, um anzugeben, dass eine synchrone Funktion abgeschlossen ist. HINWEIS: res.end() wird ebenfalls unterstützt und tut dasselbe.
sendStatus() Diese Methode ist als veraltet markiert. Es legt den Statuscode fest und ruftcontext.done() auf, um anzugeben, dass eine synchrone Funktion abgeschlossen ist.
json() Diese Methode ist als veraltet markiert. Es legt „content-type“ auf „application/json“ fest, legt den Textkörper fest und ruft context.done() auf, um anzugeben, dass eine synchrone Funktion abgeschlossen ist.

Die Antwort kann auf verschiedene Arten festgelegt werden:

  • Als einfache Schnittstelle mit dem Typ HttpResponseInit: Diese Option ist die präziseste Methode zum Zurückgeben von Antworten.

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

    Die HttpResponseInit-Schnittstelle weist die folgenden Eigenschaften auf:

    Eigenschaft Typ BESCHREIBUNG
    body BodyInit (optional) HTTP-Antworttextkörper als ArrayBuffer, AsyncIterable<Uint8Array>, Blob, FormData, Iterable<Uint8Array>, NodeJS.ArrayBufferView, URLSearchParams, null oder string.
    jsonBody any (optional) Ein JSON-serialisierbarer HTTP-Antworttextkörper. Wenn sie gesetzt ist, wird die HttpResponseInit.body-Eigenschaft zugunsten dieser Eigenschaft ignoriert.
    status number (optional) HTTP-Antwortstatuscode. Wenn nicht festgelegt, ist der Standardwert 200.
    headers HeadersInit (optional) HTTP-Antwortheader.
    cookies Cookie[] (optional) HTTP-Antwortcookies.
  • Als Klasse vom Typ HttpResponse: Diese Option stellt Hilfsmethoden zum Lesen und Ändern verschiedener Teile der Antwort bereit, z. B. der Header.

    const response = new HttpResponse({ body: `Hello, world!` });
    response.headers.set('content-type', 'application/json');
    return response;
    

    Die HttpResponse-Klasse akzeptiert ein optionales HttpResponseInit-Element als Argument für ihren Konstruktor und weist die folgenden Eigenschaften auf:

    Eigenschaft Typ BESCHREIBUNG
    status number HTTP-Antwortstatuscode.
    headers Headers HTTP-Antwortheader.
    cookies Cookie[] HTTP-Antwortcookies.
    body ReadableStream | null Textkörper als lesbarer Stream.
    bodyUsed boolean Ein boolescher Wert, der angibt, ob aus dem Textkörper bereits gelesen wurde.

HTTP-Datenströme

HTTP-Streams sind ein Feature, welches das Verarbeiten großer Daten, das Streamen von OpenAI-Antworten, das Bereitstellen dynamischer Inhalte und die Unterstützung anderer essentieller HTTP-Szenarien erleichtert. Sie können Anforderungen und Antworten von HTTP-Endpunkten in Ihrer Node.js-Funktions-App streamen. Verwenden Sie HTTP-Streams in Szenarien, in denen Ihre App Echtzeitaustausch und Interaktion zwischen Client und Server über HTTP erfordert. Sie können auch HTTP-Streams verwenden, um die beste Leistung und Zuverlässigkeit für Ihre Apps zu erzielen, wenn Sie HTTP verwenden.

Wichtig

HTTP-Streams werden im v3-Modell nicht unterstützt. Führen Sie ein Upgrade auf das v4-Modell durch, um das HTTP-Streamingfeature zu verwenden.

Die vorhandenen HttpRequest und HttpResponse Typen im Programmiermodell v4 unterstützen bereits verschiedene Methoden zur Behandlung des Nachrichtentexts, einschließlich als Stream.

Voraussetzungen

Aktivieren von Streams

Führen Sie die folgenden Schritte aus, um HTTP-Streams in Ihrer Funktions-App in Azure und in Ihren lokalen Projekten zu aktivieren:

  1. Wenn Sie beabsichtigen, große Datenmengen zu streamen, ändern Sie die FUNCTIONS_REQUEST_BODY_SIZE_LIMIT Einstellung in Azure. Die standardmäßig maximal zulässige Textkörpergröße ist 104857600, wodurch Ihre Anforderungen auf eine Größe von ~100 MB beschränkt werden.

  2. Fügen Sie für die lokale Entwicklung auch FUNCTIONS_REQUEST_BODY_SIZE_LIMIT zur Datei local.settings.json hinzu.

  3. Fügen Sie den folgenden Code zu Ihrer App in einer beliebigen Datei hinzu, die in Ihrem Hauptfeld enthalten ist.

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

Datenstrombeispiele

Dieses Beispiel zeigt eine HTTP-ausgelöste Funktion, die Daten über eine HTTP POST-Anforderung empfängt. Die Funktion streamt diese Daten an eine angegebene Ausgabedatei:

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!' };
    },
});

Dieses Beispiel zeigt eine HTTP-ausgelöste Funktion, die den Inhalt einer Datei als Antwort auf eingehende HTTP GET-Anforderungen streamt:

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 };
    },
});

Eine einsatzbereite Beispiel-App mit Streams finden Sie in diesem Beispiel auf GitHub.

Überlegungen zu Streams

  • Wird verwendet request.body, um den maximalen Nutzen aus der Verwendung von Datenströmen zu erhalten. Sie können Methoden wie request.text(), die immer den Textkörper als Zeichenfolge zurückgeben, weiterhin verwenden.

Hooks

Hooks werden im v3-Modell nicht unterstützt. Führen Sie ein Upgrade auf das v4-Modell durch, um Hooks zu verwenden.

Verwenden Sie einen Hook, um Code an verschiedenen Stellen im Azure Functions-Lebenszyklus auszuführen. Hooks werden in der Reihenfolge ihrer Registrierung ausgeführt und können in jeder Datei in Ihrer App registriert werden. Derzeit gibt es zwei Bereiche von Hooks – „App“-Ebene und „Aufruf“-Ebene.

Aufrufhooks

Aufrufhooks werden einmal pro Aufruf Ihrer Funktion ausgeführt, entweder vor einem preInvocation-Hook oder nach einem postInvocation-Hook. Standardmäßig wird ihr Hook für alle Triggertypen ausgeführt, Sie können aber auch nach Typ filtern. Das folgende Beispiel zeigt, wie Sie einen Aufrufhook registrieren und nach Triggertyp filtern:

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

Das erste Argument für den Hookhandler ist ein Kontextobjekt, das für diesen Hooktyp spezifisch ist.

Das PreInvocationContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
inputs An den Aufruf übergebene Argumente.
functionHandler Der Funktionshandler für den Aufruf. Änderungen an diesem Wert wirken sich auf die Funktion selbst aus.
invocationContext Das an die Funktion übergebene Aufrufkontext-Objekt.
hookData Der empfohlene Ort zum Speichern und Freigeben von Daten zwischen Hooks im selben Bereich. Sie sollten einen eindeutigen Eigenschaftsnamen verwenden, damit kein Konflikt mit den Daten anderer Hooks besteht.

Das PostInvocationContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
inputs An den Aufruf übergebene Argumente.
result Das Ergebnis der Funktion. Änderungen an diesem Wert wirken sich auf das Gesamtergebnis der Funktion aus.
error Der von der Funktion ausgelöste Fehler oder null/undefiniert, wenn kein Fehler vorhanden ist. Änderungen an diesem Wert wirken sich auf das Gesamtergebnis der Funktion aus.
invocationContext Das an die Funktion übergebene Aufrufkontext-Objekt.
hookData Der empfohlene Ort zum Speichern und Freigeben von Daten zwischen Hooks im selben Bereich. Sie sollten einen eindeutigen Eigenschaftsnamen verwenden, damit kein Konflikt mit den Daten anderer Hooks besteht.

App-Hooks

App-Hooks werden einmal pro Instanz Ihrer App ausgeführt, entweder während des Starts in einem appStart-Hook oder während der Beendigung in einem appTerminate-Hook. App-Beendigungs-Hooks haben einen begrenzten Zeitraum für die Ausführung und werden nicht in allen Szenarien ausgeführt.

Die Azure Functions-Runtime unterstützt derzeit keine Kontextprotokollierung außerhalb eines Aufrufs. Verwenden Sie das Application Insights-npm-Paket, um Daten während der Hooks auf App-Ebene zu protokollieren.

Das folgende Beispiel registriert App-Hooks:

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

app.hook.appStart((context) => {
    // add your logic here
});

app.hook.appTerminate((context) => {
    // add your logic here
});

Das erste Argument für den Hookhandler ist ein Kontextobjekt, das für diesen Hooktyp spezifisch ist.

Das AppStartContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
hookData Der empfohlene Ort zum Speichern und Freigeben von Daten zwischen Hooks im selben Bereich. Sie sollten einen eindeutigen Eigenschaftsnamen verwenden, damit kein Konflikt mit den Daten anderer Hooks besteht.

Das AppTerminateContext-Objekt weist die folgenden Eigenschaften auf:

Eigenschaft Beschreibung
hookData Der empfohlene Ort zum Speichern und Freigeben von Daten zwischen Hooks im selben Bereich. Sie sollten einen eindeutigen Eigenschaftsnamen verwenden, damit kein Konflikt mit den Daten anderer Hooks besteht.

Skalierung und Parallelität

Standardmäßig überwacht Azure Functions automatisch die Auslastung Ihrer Anwendung und erstellt bei Bedarf weitere Hostinstanzen für Node.js. Azure Functions verwendet integrierte (nicht vom Benutzer konfigurierbare) Schwellenwerte für verschiedene Triggertypen, um zu entscheiden, wann Instanzen hinzugefügt werden sollen, z. B. Alter von Nachrichten und Warteschlangengröße für Warteschlangentrigger. Weitere Informationen finden Sie unter Funktionsweise von Verbrauchsplan (Verbrauchstarif) und Premium-Plan.

Dieses Skalierungsverhalten ist für zahlreiche Node.js-Anwendungen ausreichend. Für CPU-gebundene Anwendungen können Sie die Leistung durch Verwendung mehrerer Sprachworkerprozesse weiter verbessern. Mithilfe der Anwendungseinstellung FUNCTIONS_WORKER_PROCESS_COUNT können Sie die Anzahl der Workerprozesse pro Host von der Standardeinstellung 1 auf maximal 10 erhöhen. Azure Functions versucht dann, gleichzeitige Funktionsaufrufe gleichmäßig auf diese Worker zu verteilen. Dieses Verhalten macht es weniger wahrscheinlich, dass eine CPU-intensive Funktion die Ausführung anderer Funktionen blockiert. Die Einstellung gilt für jeden Host, den Azure Functions beim Skalieren Ihrer Anwendung zur Deckung des Bedarfs erstellt.

Warnung

Verwenden Sie die FUNCTIONS_WORKER_PROCESS_COUNT-Einstellung mit Bedacht. Mehrere Prozesse, die in derselben Instanz ausgeführt werden, können zu unvorhersehbarem Verhalten führen und die Ladezeiten von Funktionen erhöhen. Wenn Sie diese Einstellung verwenden, ist es sehr empfehlenswert, diese Nachteile durch die Ausführung aus einer Paketdatei auszugleichen.

Node-Version

Die aktuell von der Laufzeit verwendete Version ermitteln Sie, indem Sie process.version aus einer beliebigen Funktion protokollieren. Eine Liste der Node.js-Versionen, die von jedem Programmiermodell unterstützt werden, finden Sie unter supported versions.

Festlegen der Node-Version

Die Art und Weise, wie Sie Ihre Version von Node.js aktualisieren, hängt vom Betriebssystem ab, auf dem Ihre Funktions-App ausgeführt wird.

Bei der Ausführung unter Windows wird die Node.js-Version durch die WEBSITE_NODE_DEFAULT_VERSION-Anwendungseinstellung festgelegt. Diese Einstellung kann entweder mithilfe der Azure CLI oder im Azure-Portal aktualisiert werden.

Weitere Informationen zu den Versionen von Node.js finden Sie unter Unterstützte Versionen.

Stellen Sie vor dem Upgrade Ihrer Node.js-Version sicher, dass Ihre Funktions-App mit der neuesten Version der Azure Functions-Runtime ausgeführt wird. Wenn Sie Ein Upgrade für Ihre Runtime-Version durchführen müssen, finden Sie weitere Informationen unter Migrieren von Apps von Azure Functions Version 3.x auf Version 4.x.

Führen Sie den Azure CLI-Befehl az functionapp config appsettings set aus, um die Node.js-Version für Ihre Funktions-App unter Windows zu aktualisieren:

az functionapp config appsettings set  --settings WEBSITE_NODE_DEFAULT_VERSION=~20 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME> 

Dadurch wird die WEBSITE_NODE_DEFAULT_VERSION Anwendungseinstellung auf die unterstützte LTS-Version von ~20 festgelegt.

Nachdem die Änderungen vorgenommen wurden, wird Ihre Funktions-App neu gestartet. Weitere Informationen zum Functions-Support für Node.js finden Sie unter Unterstützungsrichtlinie für die Sprachlaufzeit.

Umgebungsvariablen

Umgebungsvariablen können für Betriebsgeheimnisse (Verbindungszeichenfolgen, Schlüssel, Endpunkte usw.) oder Umgebungseinstellungen wie Profilerstellungsvariablen nützlich sein. Sie können sowohl in Ihrer lokalen als auch in Ihrer Cloud-Umgebung Umgebungsvariablen hinzufügen und über process.env in Ihrem Funktionscode auf sie zugreifen.

Im folgenden Beispiel wird die Umgebungsvariable WEBSITE_SITE_NAME festgelegt:

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

In der lokalen Entwicklungsumgebung

Wenn Sie das Funktionsprojekt lokal ausführen, enthält es eine local.settings.json-Datei, in der Sie die Umgebungsvariablen im Values-Objekt speichern.

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

In der Azure-Cloudumgebung

Wenn die Ausführung in Azure erfolgt, können Sie mithilfe der Funktions-App Anwendungseinstellungen festlegen und verwenden, z. B. Dienstverbindungszeichenfolgen. Diese Einstellungen werden während der Ausführung als Umgebungsvariablen bereitgestellt.

Es gibt mehrere Möglichkeiten zum Hinzufügen, Aktualisieren und Löschen von Funktionen-App-Einstellungen:

Zur Durchführung von Änderungen an den Funktions-App-Einstellungen muss Ihre Funktions-App neu gestartet werden.

Worker-Umgebungsvariablen

Es gibt mehrere Functions-Umgebungsvariablen, die für Node.js spezifisch sind:

languageWorkers__node__arguments

Mit dieser Einstellung können Sie benutzerdefinierte Argumente angeben, wenn Sie ihren Node.js Prozess starten. Sie wird meist lokal verwendet, um den Worker im Debug-Modus zu starten, kann aber auch in Azure verwendet werden, wenn Sie benutzerdefinierte Argumente benötigen.

Warnung

Vermeiden Sie nach Möglichkeit die Verwendung von languageWorkers__node__arguments in Azure, da sich dies negativ auf die Kaltstartzeiten auswirken kann. Anstatt vorbereitete Worker zu verwenden, muss die Laufzeitumgebung einen neuen Worker von Grund auf mit Ihren benutzerdefinierten Argumenten starten.

logging__logLevel__Worker

Mit dieser Einstellung wird die Standardprotokollebene für Node.js-spezifische Workerprotokolle angepasst. Standardmäßig werden nur Warnungs- oder Fehlerprotokolle angezeigt, aber Sie können sie auf information oder debug festlegen, um Probleme mit dem Node.js-Worker zu diagnostizieren. Weitere Informationen finden Sie unter Konfigurieren von Protokollierungsebenen.

ECMAScript-Module (Vorschau)

Hinweis

ECMAScript-Module sind derzeit eine Previewfunktion in Node.js 14 oder höher in Azure Functions.

ECMAScript-Module (ES-Module) sind das neue offizielle Standardmodulsystem für Node.js. Bisher wird in den Codebeispielen in diesem Artikel die CommonJS-Syntax verwendet. Wenn Sie Azure Functions in Node.js 14 oder höher ausführen, können Sie zum Schreiben Ihrer Funktionen auch die Syntax von ES-Modulen verwenden.

Wenn Sie ES-Module in einer Funktion verwenden möchten, ändern Sie den Dateinamen so, dass als Erweiterung .mjs verwendet wird. Die folgende Beispieldatei index.mjs ist eine per HTTP ausgelöste Funktion, die mit der ES-Modulsyntax die Bibliothek uuid importiert und einen Wert zurückgibt.

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
});

Konfigurieren des Funktionseinstiegspunkts

Die function.json-Eigenschaften scriptFile und entryPoint können verwendet werden, um den Speicherort und den Namen Ihrer exportierten Funktion zu konfigurieren. Die Eigenschaft scriptFile ist erforderlich, wenn Sie TypeScript verwenden und sollte auf das kompilierte JavaScript verweisen.

Verwenden von scriptFile

Standardmäßig wird eine JavaScript-Funktion aus der Datei index.js ausgeführt, einer Datei, die sich das gleiche übergeordnete Verzeichnis mit der entsprechenden Datei function.json teilt.

scriptFile kann verwendet werden, um eine Ordnerstruktur zu erhalten, die wie im folgenden Beispiel aussieht:

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

Die Datei function.json für myFirstFunction sollte eine scriptFile-Eigenschaft enthalten, die auf Datei mit der exportierten Funktion verweist, die ausgeführt werden soll.

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

Verwenden von entryPoint

Im Modell v3 muss eine Funktion mit module.exports exportiert werden, damit sie gefunden und ausgeführt werden kann. Standardmäßig ist die Funktion, die ausgeführt wird, wenn sie ausgelöst wird, der einzige Export aus dieser Datei, der Export mit dem Namen run oder der Export mit dem Namen index. Das folgende Beispiel setzt entryPoint in function.json auf einen benutzerdefinierten Wert, „logHello“:

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

module.exports = { logHello };

Lokales Debugging

Für das lokale Debugging wird die Verwendung von VS Code empfohlen, das Ihren Node.js-Prozess automatisch im Debug-Modus startet und sich für Sie an den Prozess anhängt. Weitere Informationen finden Sie unter Lokales Ausführen der Funktion.

Wenn Sie ein anderes Tool zum Debuggen verwenden oder Ihren Node.js-Prozess manuell im Debug-Modus starten möchten, fügen Sie "languageWorkers__node__arguments": "--inspect" unter Values in Ihrer local.settings.json hinzu. Das Argument --inspect weist Node.js an, standardmäßig an Port 9229 auf einen Debug-Client zu lauschen. Weitere Informationen finden Sie in der Anleitung zum Debuggen von Node.js.

Empfehlungen

In diesem Abschnitt werden mehrere wirkungsvolle Muster für Node.js-Apps beschrieben, die Sie befolgen sollten.

Auswählen von App Service-Plänen mit einzelner vCPU

Wenn Sie eine Funktions-App erstellen, die den App Service-Plan verwendet, sollten Sie statt eines Plans mit mehreren vCPUs einen Plan mit einer einzelnen vCPU auswählen. Node.js-Funktionen werden derzeit von Functions effizienter auf VMs mit einer einzelnen vCPU ausgeführt. Die Verwendung größerer VMs führt nicht zu den erwarteten Leistungsverbesserungen. Bei Bedarf können Sie manuell aufskalieren, indem Sie weitere Instanzen virtueller Computer mit einer einzelnen vCPU hinzufügen. Sie können aber auch die automatische Skalierung aktivieren. Weitere Informationen finden Sie unter Manuelles oder automatisches Skalieren der Instanzenzahl.

Ausführen aus einer Paketdatei

Bei der Entwicklung von Azure Functions im serverlosen Hostingmodell sind Kaltstarts Realität. Der Begriff Kaltstart bezieht sich auf den ersten Start Ihrer Funktions-App nach einer Zeit der Inaktivität, der länger dauert. Insbesondere bei Node.js-Apps mit großen Abhängigkeitsbäumen kann ein Kaltstart erheblich länger dauern. Nach Möglichkeit sollten Sie die Funktionen als Paketdatei ausführen, um den Prozess des Kaltstarts zu beschleunigen. Viele Bereitstellungsmethoden verwenden dieses Modell standardmäßig, aber wenn Sie große Kaltstarts haben, sollten Sie sicherstellen, dass diese Ausführung verwendet wird.

Verwenden eines einzelnen statischen Clients

Wenn Sie einen dienstspezifischen Client in einer Azure Functions-Anwendung verwenden, erstellen Sie nicht bei jedem Funktionsaufruf einen neuen Client, da Sie an Verbindungsgrenzen stoßen können. Erstellen Sie stattdessen einen einzelnen, statischen Client im globalen Bereich. Weitere Informationen finden Sie unter Verwalten von Verbindungen in Azure Functions.

Verwenden von async und await

Beim Schreiben von Azure Functions in Node.js sollten Sie Code schreiben, in dem Sie die Schlüsselwörter async und await verwenden. Wenn Sie zum Schreiben von Code async und await anstelle von Rückrufen oder .then und .catch mit Zusagen verwenden, können Sie zwei häufige Probleme vermeiden:

  • Das Auslösen von nicht abgefangenen Ausnahmen, die zu einem Absturz des Node.js-Prozesses führen und sich unter Umständen auf die Ausführung anderer Funktionen auswirken.
  • Unerwartetes Verhalten, z. B. fehlende Protokolle aus context.log, das durch nicht ordnungsgemäß erwartete asynchrone Aufrufe verursacht wird.

Im folgenden Beispiel wird die asynchrone fs.readFile-Methode mit einer Error-First-Rückruffunktion als zweitem Parameter aufgerufen. Durch diesen Code werden die beiden zuvor erwähnten Probleme verursacht. Eine Ausnahme, die nicht explizit im richtigen Bereich abgefangen wird, kann zum Absturz des gesamten Prozesses führen (Problem #1). Wird zurückgegeben, ohne sicherzustellen, dass der Rückruf abgeschlossen ist, bedeutet die HTTP-Antwort manchmal einen leeren Textkörper (Problem Nr. 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 };
    },
});

Im folgenden Beispiel wird die asynchrone fs.readFile-Methode mit einer Error-First-Rückruffunktion als zweitem Parameter aufgerufen. Durch diesen Code werden die beiden zuvor erwähnten Probleme verursacht. Eine Ausnahme, die nicht explizit im richtigen Bereich abgefangen wird, kann zum Absturz des gesamten Prozesses führen (Problem #1). Der Aufruf der veralteten context.done()-Methode außerhalb des Geltungsbereichs des Callbacks kann signalisieren, dass die Funktion beendet ist, bevor die Datei gelesen wurde (Problem #2). Bei diesem Beispiel führt ein zu frühes Aufrufen von context.done() zu fehlenden Protokolleinträgen, die mit Data from file: beginnen.

// 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();
}

Verwenden Sie die Schlüsselwörter async und await, um diese beiden Probleme zu vermeiden. Die meisten APIs im Node.js-Ökosystem wurden so umgestaltet, dass sie Promises in irgendeiner Form unterstützen. Zum Beispiel bietet Node.js ab v14 eine fs/promises-API, die die fs-Callback-API ersetzt.

Im folgenden Beispiel verursachen unbehandelte Ausnahmen, die während der Funktionsausführung ausgelöst werden, nur bei dem Aufruf einen Fehler, der die Ausnahme ausgelöst hat. Das Schlüsselwort await bedeutet, dass Schritte, die auf readFile folgen, erst nach dessen Abschluss ausgeführt werden.

// 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;
        }
    },
});

Bei Verwendung von async und await ist es auch nicht erforderlich, den Rückruf context.done() aufzurufen.

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

Problembehandlung

Weitere Informationen finden Sie im Node.js-Leitfaden zur Problembehandlung.

Nächste Schritte

Weitere Informationen finden Sie in den folgenden Ressourcen: