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 Eigenschaftname
, die infunction.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 Eigenschaftname
, die infunction.json
definiert 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
(infunction.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 aufcontext.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
undbinary
unterstützt (nichtstream
) - Bei HTTP-Eingaben wird die Eigenschaft
dataType
ignoriert. Verwenden Sie stattdessen Eigenschaften für dasrequest
objekt, 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-context
objekt ü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.json definiert 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.bindings
objekt 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-context
objekt übergeben, das Informationen über Ihren Aufruf und die für die Protokollierung verwendeten Methoden enthält. Im v4-Modell ist das context
objekt 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 HttpResponse
objekte 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 aufcontext.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 Ihrerfunction.json
), können Sie die Antwort direkt zurückgeben, anstatt sie aufcontext
festzulegen.{ "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 aufcontext.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 implizitcontext.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.res
objekt 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
oderstring
.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 optionalesHttpResponseInit
-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
- Version 4.3.0 oder höher des
@azure/functions
npm-Pakets. - Azure Functions Runtime Version 4.28 oder höher.
- Azure Functions Core Tools Version 4.0.5530 oder höher, welche die richtige Laufzeitversion enthält.
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:
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 ist104857600
, wodurch Ihre Anforderungen auf eine Größe von ~100 MB beschränkt werden.Fügen Sie für die lokale Entwicklung auch
FUNCTIONS_REQUEST_BODY_SIZE_LIMIT
zur Datei local.settings.json hinzu.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 wierequest.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: