Utvecklarguide för Azure Functions Node.js
Den här guiden är en introduktion till att utveckla Azure Functions med hjälp av JavaScript eller TypeScript. Artikeln förutsätter att du redan har läst utvecklarguiden för Azure Functions.
Viktigt!
Innehållet i den här artikeln ändras baserat på ditt val av Node.js programmeringsmodell i väljaren överst på den här sidan. Den version du väljer ska matcha den version av @azure/functions
npm-paketet som du använder i din app. Om du inte har det paketet i listan package.json
är standardvärdet v3. Läs mer om skillnaderna mellan v3 och v4 i migreringsguiden.
Som Node.js utvecklare kanske du också är intresserad av någon av följande artiklar:
Komma igång | Begrepp | Handledd utbildning |
---|---|---|
Att tänka på
- Programmeringsmodellen Node.js ska inte förväxlas med Azure Functions-körningen:
- Programmeringsmodell: Definierar hur du skapar din kod och är specifik för JavaScript och TypeScript.
- Körning: Definierar underliggande beteende för Azure Functions och delas mellan alla språk.
- Versionen av programmeringsmodellen är strikt kopplad till versionen av
@azure/functions
npm-paketet. Den är versionshanterad oberoende av körningen. Både körningen och programmeringsmodellen använder nummer 4 som sin senaste huvudversion, men det är en tillfällighet. - Du kan inte blanda programmeringsmodellerna v3 och v4 i samma funktionsapp. Så snart du registrerar en v4-funktion i din app ignoreras alla v3-funktioner som är registrerade i function.json filer.
Versioner som stöds
I följande tabell visas varje version av Node.js programmeringsmodell tillsammans med de versioner av Azure Functions-körningen som stöds och Node.js.
Programmeringsmodellversion | Supportnivå | Functions Runtime-version | Node.js Version | beskrivning |
---|---|---|---|---|
4.x | Allmän tillgänglighet | 4.25+ | 20.x, 18.x | Har stöd för en flexibel filstruktur och kodcentrerad metod för utlösare och bindningar. |
3.x | Allmän tillgänglighet | 4.x | 20.x, 18.x, 16.x, 14.x | Kräver en specifik filstruktur med dina utlösare och bindningar deklarerade i en "function.json"-fil |
2.x | saknas | 3.x | 14.x, 12.x, 10.x | Supporten upphörde den 13 december 2022. Mer information finns i Funktionsversioner . |
1.x | saknas | 2.x | 10.x, 8.x | Supporten upphörde den 13 december 2022. Mer information finns i Funktionsversioner . |
Mappstrukturen
Den nödvändiga mappstrukturen för ett JavaScript-projekt ser ut som i följande exempel:
<project_root>/
| - .vscode/
| - node_modules/
| - myFirstFunction/
| | - index.js
| | - function.json
| - mySecondFunction/
| | - index.js
| | - function.json
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
Huvudprojektmappen, <project_root>, kan innehålla följande filer:
- .vscode/: (valfritt) innehåller den lagrade Visual Studio Code-konfigurationen. Mer information finns i Visual Studio Code-inställningar.
- myFirstFunction/function.json: Innehåller konfiguration för funktionens utlösare, indata och utdata. Namnet på katalogen avgör namnet på din funktion.
- myFirstFunction/index.js: Lagrar funktionskoden. Information om hur du ändrar den här standardsökvägen finns i använda scriptFile.
- .funcignore: (Valfritt) Deklarerar filer som inte ska publiceras i Azure. Den här filen innehåller vanligtvis .vscode/ för att ignorera redigeringsinställningen, testa/ ignorera testfall och local.settings.json för att förhindra att lokala appinställningar publiceras.
- host.json: Innehåller konfigurationsalternativ som påverkar alla funktioner i en funktionsappinstans. Den här filen publiceras till Azure. Alla alternativ stöds inte när de körs lokalt. Mer information finns i host.json.
- local.settings.json: Används för att lagra appinställningar och anslutningssträng när den körs lokalt. Den här filen publiceras inte i Azure. Mer information finns i local.settings.file.
- package.json: Innehåller konfigurationsalternativ som en lista över paketberoenden, huvudinmatningspunkten och skript.
Den rekommenderade mappstrukturen för ett JavaScript-projekt ser ut som i följande exempel:
<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
Huvudprojektmappen, <project_root>, kan innehålla följande filer:
- .vscode/: (valfritt) innehåller den lagrade Visual Studio Code-konfigurationen. Mer information finns i Visual Studio Code-inställningar.
- src/functions/: Standardplatsen för alla funktioner och deras relaterade utlösare och bindningar.
- test/: (Valfritt) Innehåller testfallen för din funktionsapp.
- .funcignore: (Valfritt) Deklarerar filer som inte ska publiceras i Azure. Den här filen innehåller vanligtvis .vscode/ för att ignorera redigeringsinställningen, testa/ ignorera testfall och local.settings.json för att förhindra att lokala appinställningar publiceras.
- host.json: Innehåller konfigurationsalternativ som påverkar alla funktioner i en funktionsappinstans. Den här filen publiceras till Azure. Alla alternativ stöds inte när de körs lokalt. Mer information finns i host.json.
- local.settings.json: Används för att lagra appinställningar och anslutningssträng när den körs lokalt. Den här filen publiceras inte i Azure. Mer information finns i local.settings.file.
- package.json: Innehåller konfigurationsalternativ som en lista över paketberoenden, huvudinmatningspunkten och skript.
Registrera en funktion
V3-modellen registrerar en funktion baserat på förekomsten av två filer. Först behöver du en function.json
fil som finns i en mapp en nivå ned från appens rot. För det andra behöver du en JavaScript-fil som exporterar din funktion. Som standard letar modellen efter en index.js
fil i samma mapp som din function.json
. Om du använder TypeScript måste du använda scriptFile
egenskapen i function.json
för att peka på den kompilerade JavaScript-filen. Information om hur du anpassar filplatsen eller exportnamnet för funktionen finns i konfigurera din funktions startpunkt.
Funktionen som du exporterar ska alltid deklareras som en async function
i v3-modellen. Du kan exportera en synkron funktion, men sedan måste du anropa context.done()
för att signalera att funktionen har slutförts, vilket är inaktuellt och inte rekommenderas.
Funktionen skickas ett anrop context
som det första argumentet och dina indata som återstående argument.
Följande exempel är en enkel funktion som loggar att den utlöstes och svarar med Hello, world!
:
{
"bindings": [
{
"type": "httpTrigger",
"direction": "in",
"name": "req",
"authLevel": "anonymous",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
module.exports = async function (context, request) {
context.log('Http function was triggered.');
context.res = { body: 'Hello, world!' };
};
Programmeringsmodellen läser in dina funktioner baserat på fältet main
i din package.json
. Du kan ange fältet main
till en enskild fil eller flera filer med hjälp av ett globmönster. I följande tabell visas exempelvärden för fältet main
:
Exempel | beskrivning |
---|---|
src/index.js |
Registrera funktioner från en enda rotfil. |
src/functions/*.js |
Registrera varje funktion från en egen fil. |
src/{index.js,functions/*.js} |
En kombination där du registrerar varje funktion från en egen fil, men du fortfarande har en rotfil för allmän kod på appnivå. |
För att kunna registrera en funktion måste du importera app
objektet från @azure/functions
npm-modulen och anropa metoden som är specifik för din utlösartyp. Det första argumentet när du registrerar en funktion är funktionsnamnet. Det andra argumentet är ett options
objekt som anger konfiguration för utlösaren, hanteraren och andra indata eller utdata. I vissa fall där utlösarkonfiguration inte behövs kan du skicka hanteraren direkt som det andra argumentet i stället för ett options
objekt.
Registrering av en funktion kan göras från valfri fil i projektet, så länge filen läses in (direkt eller indirekt) baserat på fältet main
i filen package.json
. Funktionen bör registreras i ett globalt omfång eftersom du inte kan registrera funktioner när körningarna har startats.
Följande exempel är en enkel funktion som loggar att den utlöstes och svarar med Hello, world!
:
const { app } = require('@azure/functions');
app.http('helloWorld1', {
methods: ['POST', 'GET'],
handler: async (request, context) => {
context.log('Http function was triggered.');
return { body: 'Hello, world!' };
}
});
Indata och utdata
Din funktion måste ha exakt en primär indata som kallas utlösaren. Den kan också ha sekundära indata och/eller utdata. Indata och utdata konfigureras i dina function.json
filer och kallas även bindningar.
Indata
Indata är bindningar med direction
värdet in
. Den största skillnaden mellan en utlösare och en sekundär indata är att type
för en utlösare slutar i Trigger
, till exempel typ blobTrigger
vs typ blob
. De flesta funktioner använder bara en utlösare och inte många sekundära indatatyper stöds.
Indata kan nås på flera sätt:
[Rekommenderas] Som argument som skickas till funktionen: Använd argumenten i samma ordning som de definieras i
function.json
. Egenskapenname
som definieras ifunction.json
behöver inte matcha namnet på argumentet, även om det rekommenderas för organisationens skull.module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
Som egenskaper för
context.bindings
: Använd nyckeln som matchar egenskapenname
som definieras ifunction.json
.module.exports = async function (context) { context.log("This is myTrigger: " + context.bindings.myTrigger); context.log("This is myInput: " + context.bindings.myInput); context.log("This is myOtherInput: " + context.bindings.myOtherInput); };
Utdata
Utdata är bindningar med direction
inställt på out
och kan anges på flera sätt:
[Rekommenderas för enkla utdata] Returnera värdet direkt: Om du använder en asynkron funktion kan du returnera värdet direkt. Du måste ändra egenskapen för
name
utdatabindningen till$return
i som ifunction.json
följande exempel:{ "name": "$return", "type": "http", "direction": "out" }
module.exports = async function (context, request) { return { body: "Hello, world!" }; }
[Rekommenderas för flera utdata] Returnera ett objekt som innehåller alla utdata: Om du använder en asynkron funktion kan du returnera ett objekt med en egenskap som matchar namnet på varje bindning i .
function.json
I följande exempel används utdatabindningar med namnet "httpResponse" och "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }
module.exports = async function (context, request) { let message = 'Hello, world!'; return { httpResponse: { body: message }, queueOutput: message }; };
Ange värden på
context.bindings
: Om du inte använder en asynkron funktion eller om du inte vill använda föregående alternativ kan du ange värden direkt på , där nyckeln matchar namnet påcontext.bindings
bindningen. I följande exempel används utdatabindningar med namnet "httpResponse" och "queueOutput":{ "name": "httpResponse", "type": "http", "direction": "out" }, { "name": "queueOutput", "type": "queue", "direction": "out", "queueName": "helloworldqueue", "connection": "storage_APPSETTING" }
module.exports = async function (context, request) { let message = 'Hello, world!'; context.bindings.httpResponse = { body: message }; context.bindings.queueOutput = message; };
Datatyp för bindningar
Du kan använda dataType
egenskapen på en indatabindning för att ändra typen av indata, men den har vissa begränsningar:
- I Node.js stöds endast
string
ochbinary
(stream
är inte) - För HTTP-indata ignoreras egenskapen
dataType
. Använd i stället egenskaper förrequest
objektet för att hämta brödtexten i önskat format. Mer information finns i HTTP-begäran.
I följande exempel på en lagringsköutlösare är standardtypen myQueueItem
en string
, men om du anger dataType
till binary
ändras typen till en 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');
}
};
Din funktion måste ha exakt en primär indata som kallas utlösaren. Den kan också ha sekundära indata, ett primärt utdata som kallas returutdata och/eller sekundära utdata. Indata och utdata kallas även bindningar utanför kontexten för Node.js programmeringsmodell. Före v4 för modellen konfigurerades dessa bindningar i function.json
filer.
Utlösarindata
Utlösaren är den enda obligatoriska indata eller utdata. För de flesta utlösartyper registrerar du en funktion med hjälp av en metod för objektet app
med namnet efter utlösartypen. Du kan ange konfiguration som är specifik för utlösaren direkt på options
argumentet. Med en HTTP-utlösare kan du till exempel ange en väg. Under körningen skickas värdet som motsvarar den här utlösaren som det första argumentet till hanteraren.
const { app } = require('@azure/functions');
app.http('helloWorld1', {
route: 'hello/world',
handler: async (request, context) => {
...
}
});
Returnera utdata
Returutdata är valfria och i vissa fall konfigurerade som standard. Till exempel har en HTTP-utlösare som registrerats med app.http
konfigurerats för att returnera ett HTTP-svarsutdata automatiskt. För de flesta utdatatyper anger du returkonfigurationen options
för argumentet med hjälp av objektet som output
exporteras från modulen @azure/functions
. Under körningen anger du dessa utdata genom att returnera dem från hanteraren.
I följande exempel används en timerutlösare och utdata från en lagringskö:
const { app, output } = require('@azure/functions');
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: output.storageQueue({
connection: 'storage_APPSETTING',
...
}),
handler: (myTimer, context) => {
return { hello: 'world' }
}
});
Extra indata och utdata
Förutom utlösaren och returen kan du ange extra indata eller utdata för options
argumentet när du registrerar en funktion. Objekten input
och output
som exporteras från modulen @azure/functions
innehåller typspecifika metoder som hjälper dig att konstruera konfigurationen. Under körningen får eller anger du värdena med context.extraInputs.get
eller context.extraOutputs.set
och skickar det ursprungliga konfigurationsobjektet som det första argumentet.
Följande exempel är en funktion som utlöses av en lagringskö, med en extra lagringsblobinindata som kopieras till en extra lagringsblobutdata. Kömeddelandet ska vara namnet på en fil och ersätts {queueTrigger}
som det blobnamn som ska kopieras, med hjälp av ett bindningsuttryck.
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);
}
});
Allmänna indata och utdata
Objekten app
, trigger
, input
och som output
exporteras av modulen @azure/functions
innehåller typspecifika metoder för de flesta typer. För alla typer som inte stöds tillhandahålls en generic
metod som gör att du kan ange konfigurationen manuellt. Metoden generic
kan också användas om du vill ändra standardinställningarna som tillhandahålls av en typspecifik metod.
Följande exempel är en enkel HTTP-utlöst funktion med generiska metoder i stället för typspecifika metoder.
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!` };
}
});
Anropskontext
Varje anrop av funktionen skickas ett anropsobjekt context
som används för att läsa indata, ange utdata, skriva till loggar och läsa olika metadata. I v3-modellen är kontextobjektet alltid det första argumentet som skickas till hanteraren.
Objektet context
har följande egenskaper:
Property | beskrivning |
---|---|
invocationId |
ID:t för den aktuella funktionsanropet. |
executionContext |
Se körningskontext. |
bindings |
Se bindningar. |
bindingData |
Metadata om utlösarindata för det här anropet, inte själva värdet. En händelsehubbutlösare har till exempel en enqueuedTimeUtc egenskap. |
traceContext |
Kontexten för distribuerad spårning. Mer information finns i Trace Context . |
bindingDefinitions |
Konfigurationen av dina indata och utdata enligt definitionen i function.json . |
req |
Se HTTP-begäran. |
res |
Se HTTP-svar. |
context.executionContext
Objektet context.executionContext
har följande egenskaper:
Property | beskrivning |
---|---|
invocationId |
ID:t för den aktuella funktionsanropet. |
functionName |
Namnet på den funktion som anropas. Namnet på mappen som innehåller function.json filen avgör namnet på funktionen. |
functionDirectory |
Mappen som innehåller function.json filen. |
retryContext |
Se kontext för återförsök. |
context.executionContext.retryContext
Objektet context.executionContext.retryContext
har följande egenskaper:
Property | beskrivning |
---|---|
retryCount |
Ett tal som representerar det aktuella återförsöksförsöket. |
maxRetryCount |
Maximalt antal gånger som en körning görs på nytt. Ett värde för -1 medel för att försöka igen på obestämd tid. |
exception |
Undantag som orsakade återförsöket. |
context.bindings
Objektet context.bindings
används för att läsa indata eller ange utdata. Följande exempel är en lagringsköutlösare som använder context.bindings
för att kopiera en lagringsblobin till en lagringsblobutdata. Kömeddelandets innehåll ersätts {queueTrigger}
som det filnamn som ska kopieras med hjälp av ett bindningsuttryck.
{
"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
Metoden context.done
är inaktuell. Innan asynkrona funktioner stöds skulle du signalera att funktionen är klar genom att anropa context.done()
:
module.exports = function (context, request) {
context.log("this pattern is now deprecated");
context.done();
};
Nu rekommenderar vi att du tar bort anropet till context.done()
och markerar funktionen som asynkron så att den returnerar ett löfte (även om du inte await
gör något). Så snart funktionen har slutförts (med andra ord matchar det returnerade löftet) vet v3-modellen att funktionen är klar.
module.exports = async function (context, request) {
context.log("you don't need context.done or an awaited call")
};
Varje anrop av funktionen skickas ett anropsobjekt context
med information om ditt anrop och metoder som används för loggning. I v4-modellen context
är objektet vanligtvis det andra argumentet som skickas till hanteraren.
Klassen InvocationContext
har följande egenskaper:
Property | beskrivning |
---|---|
invocationId |
ID:t för den aktuella funktionsanropet. |
functionName |
Namnet på funktionen. |
extraInputs |
Används för att hämta värdena för extra indata. Mer information finns i extra indata och utdata. |
extraOutputs |
Används för att ange värdena för extra utdata. Mer information finns i extra indata och utdata. |
retryContext |
Se kontext för återförsök. |
traceContext |
Kontexten för distribuerad spårning. Mer information finns i Trace Context . |
triggerMetadata |
Metadata om utlösarindata för det här anropet, inte själva värdet. En händelsehubbutlösare har till exempel en enqueuedTimeUtc egenskap. |
options |
De alternativ som används när du registrerar funktionen, när de har verifierats och med uttryckliga standardvärden angivna. |
Kontext för återförsök
Objektet retryContext
har följande egenskaper:
Property | beskrivning |
---|---|
retryCount |
Ett tal som representerar det aktuella återförsöksförsöket. |
maxRetryCount |
Maximalt antal gånger som en körning görs på nytt. Ett värde för -1 medel för att försöka igen på obestämd tid. |
exception |
Undantag som orsakade återförsöket. |
Mer information finns i retry-policies
.
Loggning
I Azure Functions rekommenderar vi att du använder context.log()
för att skriva loggar. Azure Functions integreras med Azure Application Insights för att bättre avbilda dina funktionsapploggar. Application Insights, en del av Azure Monitor, tillhandahåller faciliteter för insamling, visuell återgivning och analys av både programloggar och spårningsutdata. Mer information finns i övervaka Azure Functions.
Kommentar
Om du använder den alternativa Node.js-metoden console.log
spåras loggarna på appnivå och associeras inte med någon specifik funktion. Vi rekommenderar starkt att du använder context
för loggning i stället för console
så att alla loggar är associerade med en specifik funktion.
I följande exempel skrivs en logg på standardnivån "information", inklusive anrops-ID:
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);
Loggnivåer
Förutom standardmetoden context.log
är följande metoder tillgängliga som gör att du kan skriva loggar på specifika nivåer:
Metod | beskrivning |
---|---|
context.log.error() |
Skriver en händelse på felnivå till loggarna. |
context.log.warn() |
Skriver en händelse på varningsnivå till loggarna. |
context.log.info() |
Skriver en informationsnivåhändelse till loggarna. |
context.log.verbose() |
Skriver en händelse på spårningsnivå till loggarna. |
Metod | beskrivning |
---|---|
context.trace() |
Skriver en händelse på spårningsnivå till loggarna. |
context.debug() |
Skriver en händelse på felsökningsnivå till loggarna. |
context.info() |
Skriver en informationsnivåhändelse till loggarna. |
context.warn() |
Skriver en händelse på varningsnivå till loggarna. |
context.error() |
Skriver en händelse på felnivå till loggarna. |
Konfigurera loggnivå
Med Azure Functions kan du definiera den tröskelvärdesnivå som ska användas vid spårning och visning av loggar. Om du vill ange tröskelvärdet använder du logging.logLevel
egenskapen i host.json
filen. Med den här egenskapen kan du definiera en standardnivå som tillämpas på alla funktioner eller ett tröskelvärde för varje enskild funktion. Mer information finns i Konfigurera övervakning för Azure Functions.
Spåra anpassade data
Som standard skriver Azure Functions utdata som spårningar till Application Insights. Om du vill ha mer kontroll kan du i stället använda Application Insights Node.js SDK för att skicka anpassade data till din Application Insights-instans.
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});
};
Parametern tagOverrides
anger operation_Id
till funktionens anrops-ID. Med den här inställningen kan du korrelera alla automatiskt genererade och anpassade loggar för en viss funktionsanrop.
HTTP-utlösare
HTTP- och webhook-utlösare använder begärande- och svarsobjekt för att representera HTTP-meddelanden.
HTTP- och webhook-utlösare använder HttpRequest
och HttpResponse
objekt för att representera HTTP-meddelanden. Klasserna representerar en delmängd av hämtningsstandarden med hjälp av Node.js paketundici
.
HTTP-begäran
Begäran kan nås på flera sätt:
Som det andra argumentet för din funktion:
module.exports = async function (context, request) { context.log(`Http function processed request for url "${request.url}"`);
Från egenskapen
context.req
:module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.req.url}"`);
Från de namngivna indatabindningarna: Det här alternativet fungerar på samma sätt som alla icke HTTP-bindningar. Bindningsnamnet i
function.json
måste matcha nyckeln påcontext.bindings
, eller "request1" i följande exempel:{ "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}"`);
Objektet HttpRequest
har följande egenskaper:
Property | Type | Beskrivning |
---|---|---|
method |
string |
HTTP-begärandemetod som används för att anropa den här funktionen. |
url |
string |
Begärande-URL. |
headers |
Record<string, string> |
HTTP-begärandehuvuden. Det här objektet är skiftlägeskänsligt. Vi rekommenderar att du använder request.getHeader('header-name') i stället, vilket är skiftlägesokänsligt. |
query |
Record<string, string> |
Frågesträngsparameternycklar och värden från URL:en. |
params |
Record<string, string> |
Dirigera parameternycklar och värden. |
user |
HttpRequestUser | null |
Objekt som representerar inloggad användare, antingen via Functions-autentisering, SWA-autentisering eller null när ingen sådan användare är inloggad. |
body |
Buffer | string | any |
Om medietypen är "application/octet-stream" eller "multipart/*" body är en buffert. Om värdet är en JSON-parsningsbaserad sträng body är det parsade objektet. Annars body är en sträng. |
rawBody |
string |
Brödtexten som en sträng. Trots namnet returnerar den här egenskapen inte någon buffert. |
bufferBody |
Buffer |
Brödtexten som en buffert. |
Begäran kan nås som det första argumentet till din hanterare för en HTTP-utlöst funktion.
async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
Objektet HttpRequest
har följande egenskaper:
Property | Type | Beskrivning |
---|---|---|
method |
string |
HTTP-begärandemetod som används för att anropa den här funktionen. |
url |
string |
Begärande-URL. |
headers |
Headers |
HTTP-begärandehuvuden. |
query |
URLSearchParams |
Frågesträngsparameternycklar och värden från URL:en. |
params |
Record<string, string> |
Dirigera parameternycklar och värden. |
user |
HttpRequestUser | null |
Objekt som representerar inloggad användare, antingen via Functions-autentisering, SWA-autentisering eller null när ingen sådan användare är inloggad. |
body |
ReadableStream | null |
Brödtext som en läsbar ström. |
bodyUsed |
boolean |
Ett booleskt värde som anger om brödtexten redan är läst. |
För att få åtkomst till en begärans eller ett svars brödtext kan följande metoder användas:
Metod | Returtyp |
---|---|
arrayBuffer() |
Promise<ArrayBuffer> |
blob() |
Promise<Blob> |
formData() |
Promise<FormData> |
json() |
Promise<unknown> |
text() |
Promise<string> |
Kommentar
Brödtextfunktionerna kan bara köras en gång. efterföljande anrop matchas med tomma strängar/ArrayBuffers.
HTTP-svar
Svaret kan anges på flera sätt:
Ange egenskapen
context.res
:module.exports = async function (context, request) { context.res = { body: `Hello, world!` };
Returnera svaret: Om funktionen är asynkron och du anger bindningsnamnet till
$return
i kanfunction.json
du returnera svaret direkt i stället för att ange det påcontext
.{ "type": "http", "direction": "out", "name": "$return" }
module.exports = async function (context, request) { return { body: `Hello, world!` };
Ange den namngivna utdatabindningen: Det här alternativet fungerar på samma sätt som alla icke HTTP-bindningar. Bindningsnamnet i
function.json
måste matcha nyckeln påcontext.bindings
, eller "response1" i följande exempel:{ "type": "http", "direction": "out", "name": "response1" }
module.exports = async function (context, request) { context.bindings.response1 = { body: `Hello, world!` };
Anrop
context.res.send()
: Det här alternativet är inaktuellt. Den anroparcontext.done()
implicit och kan inte användas i en asynkron funktion.module.exports = function (context, request) { context.res.send(`Hello, world!`);
Om du skapar ett nytt objekt när du ställer in svaret måste objektet matcha HttpResponseSimple
gränssnittet, som har följande egenskaper:
Property | Type | Beskrivning |
---|---|---|
headers |
Record<string, string> (valfritt) |
HTTP-svarshuvuden. |
cookies |
Cookie[] (valfritt) |
HTTP-svarscookies. |
body |
any (valfritt) |
HTTP-svarstext. |
statusCode |
number (valfritt) |
Statuskod för HTTP-svar. Om den inte är inställd är standardvärdet 200 . |
status |
number (valfritt) |
Samma som statusCode . Den här egenskapen ignoreras om statusCode den har angetts. |
Du kan också ändra objektet context.res
utan att skriva över det. Standardobjektet context.res
använder HttpResponseFull
gränssnittet, som stöder följande metoder utöver HttpResponseSimple
egenskaperna:
Metod | beskrivning |
---|---|
status() |
Anger status. |
setHeader() |
Anger ett rubrikfält. OBS! res.set() och res.header() stöds också och gör samma sak. |
getHeader() |
Hämta ett rubrikfält. OBS! res.get() stöds också och gör samma sak. |
removeHeader() |
Tar bort en rubrik. |
type() |
Anger rubriken "innehållstyp". |
send() |
Den här metoden är inaktuell. Den anger brödtexten och anropen context.done() för att indikera att en synkroniseringsfunktion är klar. OBS! res.end() stöds också och gör samma sak. |
sendStatus() |
Den här metoden är inaktuell. Den anger statuskoden och anropen context.done() för att indikera att en synkroniseringsfunktion är klar. |
json() |
Den här metoden är inaktuell. Den anger "innehållstyp" till "application/json", anger brödtexten och anrop context.done() för att indikera att en synkroniseringsfunktion är klar. |
Svaret kan anges på flera sätt:
Som ett enkelt gränssnitt med typen
HttpResponseInit
: Det här alternativet är det mest koncisa sättet att returnera svar.return { body: `Hello, world!` };
Gränssnittet
HttpResponseInit
har följande egenskaper:Property Type Beskrivning body
BodyInit
(valfritt)HTTP-svarstext som en av ArrayBuffer
,AsyncIterable<Uint8Array>
,Blob
,FormData
,Iterable<Uint8Array>
,NodeJS.ArrayBufferView
,URLSearchParams
,null
ellerstring
.jsonBody
any
(valfritt)En JSON-serialiserbar HTTP-svarstext. Om värdet anges ignoreras egenskapen HttpResponseInit.body
till förmån för den här egenskapen.status
number
(valfritt)Statuskod för HTTP-svar. Om den inte är inställd är standardvärdet 200
.headers
HeadersInit
(valfritt)HTTP-svarshuvuden. cookies
Cookie[]
(valfritt)HTTP-svarscookies. Som en klass med typen
HttpResponse
: Det här alternativet innehåller hjälpmetoder för att läsa och ändra olika delar av svaret, till exempel rubrikerna.const response = new HttpResponse({ body: `Hello, world!` }); response.headers.set('content-type', 'application/json'); return response;
Klassen
HttpResponse
accepterar ett valfrittHttpResponseInit
som argument för konstruktorn och har följande egenskaper:Property Type Beskrivning status
number
Statuskod för HTTP-svar. headers
Headers
HTTP-svarshuvuden. cookies
Cookie[]
HTTP-svarscookies. body
ReadableStream | null
Brödtext som en läsbar ström. bodyUsed
boolean
Ett booleskt värde som anger om brödtexten redan har lästs från.
HTTP-strömmar
HTTP-strömmar är en funktion som gör det enklare att bearbeta stora data, strömma OpenAI-svar, leverera dynamiskt innehåll och stödja andra grundläggande HTTP-scenarier. Du kan strömma begäranden till och svar från HTTP-slutpunkter i din Node.js funktionsapp. Använd HTTP-strömmar i scenarier där din app kräver utbyte i realtid och interaktion mellan klient och server via HTTP. Du kan också använda HTTP-strömmar för att få bästa prestanda och tillförlitlighet för dina appar när du använder HTTP.
Viktigt!
HTTP-strömmar stöds inte i v3-modellen. Uppgradera till v4-modellen för att använda http-direktuppspelningsfunktionen.
De befintliga HttpRequest
typerna och HttpResponse
typerna i programmeringsmodellen v4 stöder redan olika sätt att hantera meddelandetexten, inklusive som en ström.
Förutsättningar
@azure/functions
NPM-paketversion 4.3.0 eller senare.- Azure Functions-körningsversion 4.28 eller senare.
- Azure Functions Core Tools version 4.0.5530 eller en senare version, som innehåller rätt körningsversion.
Aktivera strömmar
Använd de här stegen för att aktivera HTTP-strömmar i funktionsappen i Azure och i dina lokala projekt:
Om du planerar att strömma stora mängder data ändrar du inställningen
FUNCTIONS_REQUEST_BODY_SIZE_LIMIT
i Azure. Den högsta tillåtna standardstorleken för brödtexten är104857600
, vilket begränsar dina begäranden till en storlek på ~100 MB.För lokal utveckling lägger du även till
FUNCTIONS_REQUEST_BODY_SIZE_LIMIT
i filen local.settings.json.Lägg till följande kod i din app i alla filer som ingår i huvudfältet.
const { app } = require('@azure/functions'); app.setup({ enableHttpStream: true });
Stream-exempel
Det här exemplet visar en HTTP-utlöst funktion som tar emot data via en HTTP POST-begäran, och funktionen strömmar dessa data till en angiven utdatafil:
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!' };
},
});
Det här exemplet visar en HTTP-utlöst funktion som strömmar en fils innehåll som svar på inkommande HTTP GET-begäranden:
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 };
},
});
Om du vill ha en färdig exempelapp med hjälp av strömmar kan du läsa det här exemplet på GitHub.
Dataströmöverväganden
- Använd
request.body
för att få maximal nytta av att använda strömmar. Du kan fortfarande fortsätta att använda metoder somrequest.text()
, som alltid returnerar brödtexten som en sträng.
Hookar
Krokar stöds inte i v3-modellen. Uppgradera till v4-modellen för att använda krokar.
Använd en krok för att köra kod vid olika tidpunkter i Azure Functions-livscykeln. Hooks körs i den ordning de registreras och kan registreras från valfri fil i din app. Det finns för närvarande två omfång för krokar, "appnivå" och "anropsnivå".
Anropskrokar
Anropskrokar körs en gång per anrop av din funktion, antingen före i en preInvocation
krok eller efter i en postInvocation
krok. Som standard körs din hook för alla utlösartyper, men du kan också filtrera efter typ. I följande exempel visas hur du registrerar en anropskrok och filtrerar efter utlösartyp:
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}`
);
}
});
Det första argumentet för hook-hanteraren är ett kontextobjekt som är specifikt för den typen av krok.
Objektet PreInvocationContext
har följande egenskaper:
Property | beskrivning |
---|---|
inputs |
Argumenten som skickas till anropet. |
functionHandler |
Funktionshanteraren för anropet. Ändringar i det här värdet påverkar själva funktionen. |
invocationContext |
Kontextobjektet för anrop som skickas till funktionen. |
hookData |
Den rekommenderade platsen för att lagra och dela data mellan krokar i samma omfång. Du bör använda ett unikt egenskapsnamn så att det inte står i konflikt med andra hooks-data. |
Objektet PostInvocationContext
har följande egenskaper:
Property | beskrivning |
---|---|
inputs |
Argumenten som skickas till anropet. |
result |
Resultatet av funktionen. Ändringar i det här värdet påverkar funktionens övergripande resultat. |
error |
Felet som utlöses av funktionen eller null/odefinierat om det inte finns något fel. Ändringar i det här värdet påverkar funktionens övergripande resultat. |
invocationContext |
Kontextobjektet för anrop som skickas till funktionen. |
hookData |
Den rekommenderade platsen för att lagra och dela data mellan krokar i samma omfång. Du bör använda ett unikt egenskapsnamn så att det inte står i konflikt med andra hooks-data. |
Appkrokar
Appkrokar körs en gång per instans av din app, antingen under start i en appStart
krok eller under avslutning i en appTerminate
krok. Appslutkrokar har en begränsad tid att köra och körs inte i alla scenarier.
Azure Functions-körningen stöder för närvarande inte kontextloggning utanför ett anrop. Använd Application Insights npm-paketet för att logga data under appnivåkrokar.
I följande exempel registreras appkrokar:
const { app } = require('@azure/functions');
app.hook.appStart((context) => {
// add your logic here
});
app.hook.appTerminate((context) => {
// add your logic here
});
Det första argumentet för hook-hanteraren är ett kontextobjekt som är specifikt för den typen av krok.
Objektet AppStartContext
har följande egenskaper:
Property | beskrivning |
---|---|
hookData |
Den rekommenderade platsen för att lagra och dela data mellan krokar i samma omfång. Du bör använda ett unikt egenskapsnamn så att det inte står i konflikt med andra hooks-data. |
Objektet AppTerminateContext
har följande egenskaper:
Property | beskrivning |
---|---|
hookData |
Den rekommenderade platsen för att lagra och dela data mellan krokar i samma omfång. Du bör använda ett unikt egenskapsnamn så att det inte står i konflikt med andra hooks-data. |
Skalning och samtidighet
Som standard övervakar Azure Functions automatiskt belastningen på ditt program och skapar fler värdinstanser för Node.js efter behov. Azure Functions använder inbyggda tröskelvärden (inte användarkonfigurerbara) för olika utlösartyper för att bestämma när instanser ska läggas till, till exempel ålder på meddelanden och köstorlek för QueueTrigger. Mer information finns i Så här fungerar förbruknings- och Premium-abonnemangen.
Det här skalningsbeteendet räcker för många Node.js program. För CPU-bundna program kan du förbättra prestandan ytterligare med hjälp av flera språkprocesser. Du kan öka antalet arbetsprocesser per värd från standardvärdet 1 upp till högst 10 med hjälp av inställningen FUNCTIONS_WORKER_PROCESS_COUNT program. Azure Functions försöker sedan distribuera samtidiga funktionsanrop jämnt mellan dessa arbetare. Det här beteendet gör det mindre troligt att en CPU-intensiv funktion blockerar andra funktioner från att köras. Inställningen gäller för varje värd som Azure Functions skapar när du skalar ut ditt program för att möta efterfrågan.
Varning
Använd inställningen FUNCTIONS_WORKER_PROCESS_COUNT
med försiktighet. Flera processer som körs i samma instans kan leda till oförutsägbart beteende och öka funktionsbelastningstiderna. Om du använder den här inställningen rekommenderar vi starkt att du förskjuter dessa nackdelar genom att köra från en paketfil.
Nodversion
Du kan se den aktuella versionen som körningen använder genom att logga process.version
från valfri funktion. Se supported versions
en lista över Node.js versioner som stöds av varje programmeringsmodell.
Ange nodversionen
Hur du uppgraderar din Node.js version beror på vilket operativsystem funktionsappen körs på.
När den körs i Windows anges Node.js version av programinställningen WEBSITE_NODE_DEFAULT_VERSION
. Den här inställningen kan uppdateras antingen med hjälp av Azure CLI eller i Azure Portal.
Mer information om Node.js versioner finns i Versioner som stöds.
Innan du uppgraderar din Node.js version kontrollerar du att funktionsappen körs på den senaste versionen av Azure Functions-körningen. Om du behöver uppgradera körningsversionen läser du Migrera appar från Azure Functions version 3.x till version 4.x.
Kör Azure CLI-kommandot az functionapp config appsettings set
för att uppdatera den Node.js versionen för din funktionsapp som körs i Windows:
az functionapp config appsettings set --settings WEBSITE_NODE_DEFAULT_VERSION=~20 \
--name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>
Detta anger programinställningen WEBSITE_NODE_DEFAULT_VERSION
för LTS-versionen som stöds av ~20
.
När ändringarna har gjorts startas funktionsappen om. Mer information om Functions-stöd för Node.js finns i Supportprincip för språkkörning.
Miljövariabler
Miljövariabler kan vara användbara för drifthemligheter (anslutningssträng, nycklar, slutpunkter osv.) eller miljöinställningar som profileringsvariabler. Du kan lägga till miljövariabler i både lokala miljöer och molnmiljöer och komma åt dem i process.env
funktionskoden.
I följande exempel loggas WEBSITE_SITE_NAME
miljövariabeln:
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"]}`);
}
I den lokala utvecklingsmiljön
När du kör lokalt innehåller funktionsprojektet en local.settings.json
fil där du lagrar miljövariablerna i Values
objektet.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"CUSTOM_ENV_VAR_1": "hello",
"CUSTOM_ENV_VAR_2": "world"
}
}
I Azure-molnmiljö
När du kör i Azure låter funktionsappen dig ange och använda programinställningar, till exempel tjänst anslutningssträng, och exponerar dessa inställningar som miljövariabler under körningen.
Det finns flera sätt att lägga till, uppdatera och ta bort funktionsappinställningar:
Ändringar i funktionsappsinställningarna kräver att funktionsappen startas om.
Miljövariabler för arbetare
Det finns flera funktionsmiljövariabler som är specifika för Node.js:
languageWorkers__node__arguments
Med den här inställningen kan du ange anpassade argument när du startar din Node.js process. Den används oftast lokalt för att starta arbetaren i felsökningsläge, men kan också användas i Azure om du behöver anpassade argument.
Varning
Undvik om möjligt att använda languageWorkers__node__arguments
i Azure eftersom det kan ha en negativ effekt på kalla starttider. I stället för att använda förvärmda arbetare måste körningen starta en ny arbetare från grunden med dina anpassade argument.
logging__logLevel__Worker
Den här inställningen justerar standardloggnivån för Node.js specifika arbetsloggar. Som standard visas endast varnings- eller felloggar, men du kan ange det till information
eller debug
för att diagnostisera problem med Node.js arbetare. Mer information finns i konfigurera loggnivåer.
ECMAScript-moduler (förhandsversion)
Kommentar
Eftersom ECMAScript-moduler för närvarande är en förhandsversionsfunktion i Node.js 14 eller senare i Azure Functions.
ECMAScript-moduler (ES-moduler) är det nya officiella standardmodulsystemet för Node.js. Hittills använder kodexemplen i den här artikeln CommonJS-syntaxen. När du kör Azure Functions i Node.js 14 eller senare kan du välja att skriva dina funktioner med hjälp av ES-modulers syntax.
Om du vill använda ES-moduler i en funktion ändrar du dess filnamn så att det använder ett .mjs
tillägg. Följande index.mjs-filexempel är en HTTP-utlöst funktion som använder ES-modulers syntax för att importera uuid
biblioteket och returnera ett värde.
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
});
Konfigurera funktionsinmatningspunkt
Egenskaperna function.json
scriptFile
och entryPoint
kan användas för att konfigurera platsen och namnet på den exporterade funktionen. Egenskapen scriptFile
krävs när du använder TypeScript och ska peka på det kompilerade JavaScript.
Använda scriptFile
Som standard körs en JavaScript-funktion från index.js
, en fil som delar samma överordnade katalog som motsvarande function.json
.
scriptFile
kan användas för att hämta en mappstruktur som ser ut som i följande exempel:
<project_root>/
| - node_modules/
| - myFirstFunction/
| | - function.json
| - lib/
| | - sayHello.js
| - host.json
| - package.json
För function.json
myFirstFunction
bör innehålla en scriptFile
egenskap som pekar på filen med den exporterade funktionen som ska köras.
{
"scriptFile": "../lib/sayHello.js",
"bindings": [
...
]
}
Använda entryPoint
I v3-modellen måste en funktion exporteras med module.exports
för att kunna hittas och köras. Som standard är den funktion som körs när den utlöses den enda exporten från filen, exporten med namnet run
eller exporten med namnet index
. I följande exempel anges entryPoint
function.json
ett anpassat värde, "logHello":
{
"entryPoint": "logHello",
"bindings": [
...
]
}
async function logHello(context) {
context.log('Hello, world!');
}
module.exports = { logHello };
Lokal felsökning
Vi rekommenderar att du använder VS Code för lokal felsökning, vilket startar din Node.js process i felsökningsläge automatiskt och ansluter till processen åt dig. Mer information finns i Köra funktionen lokalt.
Om du använder ett annat verktyg för felsökning eller vill starta Node.js processen i felsökningsläge manuellt lägger du till "languageWorkers__node__arguments": "--inspect"
under Values
i local.settings.json. Argumentet --inspect
instruerar Node.js att lyssna efter en felsökningsklient på port 9229 som standard. Mer information finns i felsökningsguiden för Node.js.
Rekommendationer
Det här avsnittet beskriver flera effektfulla mönster för Node.js appar som vi rekommenderar att du följer.
Välj App Service-planer för enkel vCPU
När du skapar en funktionsapp som använder App Service-planen rekommenderar vi att du väljer en enda vCPU-plan i stället för en plan med flera virtuella processorer. I dag körs Functions Node.js funktioner mer effektivt på virtuella datorer med en virtuell dator och att använda större virtuella datorer ger inte de förväntade prestandaförbättringarna. Vid behov kan du skala ut manuellt genom att lägga till fler vm-instanser med en enda virtuell dator, eller så kan du aktivera autoskalning. Mer information finns i Skala instansantal manuellt eller automatiskt.
Kör från en paketfil
När du utvecklar Azure Functions i den serverlösa värdmodellen är kallstarter verklighet. Kallstart refererar till första gången funktionsappen startar efter en period av inaktivitet, vilket tar längre tid att starta. För Node.js appar med stora beroendeträd i synnerhet kan kallstart vara betydande. Kör funktionerna som en paketfil när det är möjligt för att påskynda kallstartsprocessen. Många distributionsmetoder använder den här modellen som standard, men om du upplever stora kallstarter bör du kontrollera att du kör på det här sättet.
Använda en enda statisk klient
När du använder en tjänstspecifik klient i ett Azure Functions-program ska du inte skapa en ny klient med varje funktionsanrop eftersom du kan nå anslutningsgränserna. Skapa i stället en enda statisk klient i det globala omfånget. Mer information finns i Hantera anslutningar i Azure Functions.
Använda async
och await
När du skriver Azure Functions i Node.js bör du skriva kod med hjälp av nyckelorden async
och await
. Genom att skriva kod med och async
await
i stället för återanrop eller .then
med .catch
Promises kan du undvika två vanliga problem:
- Utlöser ohanterade undantag som kraschar Node.js processen, vilket kan påverka körningen av andra funktioner.
- Oväntat beteende, till exempel saknade loggar från
context.log
, som orsakas av asynkrona anrop som inte är korrekt inväntade.
I följande exempel anropas den asynkrona metoden fs.readFile
med en fel-första återanropsfunktion som den andra parametern. Den här koden orsakar båda problemen som tidigare nämnts. Ett undantag som inte uttryckligen fångas i rätt omfång kan krascha hela processen (problem nr 1). Om du återvänder utan att återanropet har slutförts innebär det att http-svaret ibland har en tom brödtext (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 };
},
});
I följande exempel anropas den asynkrona metoden fs.readFile
med en fel-första återanropsfunktion som den andra parametern. Den här koden orsakar båda problemen som tidigare nämnts. Ett undantag som inte uttryckligen fångas i rätt omfång kan krascha hela processen (problem nr 1). Att anropa den inaktuella context.done()
metoden utanför återanropets omfång kan signalera att funktionen är klar innan filen läss (problem nr 2). I det här exemplet resulterar anrop context.done()
för tidigt i saknade loggposter som börjar med Data from file:
.
// NOT RECOMMENDED PATTERN
const fs = require('fs');
module.exports = function (context) {
fs.readFile('./hello.txt', (err, data) => {
if (err) {
context.log.error('ERROR', err);
// BUG #1: This will result in an uncaught exception that crashes the entire process
throw err;
}
context.log(`Data from file: ${data}`);
// context.done() should be called here
});
// BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
context.done();
}
Använd nyckelorden async
och await
för att undvika båda dessa problem. De flesta API:er i Node.js ekosystem har konverterats för att stödja löften i någon form. Med början i v14 tillhandahåller Node.js till exempel ett fs/promises
API för att ersätta motringnings-API:et fs
.
I följande exempel misslyckas alla ohanterade undantag som utlöses under funktionskörningen endast det enskilda anrop som utlöste undantaget. Nyckelordet await
innebär att stegen som följer readFile
bara körs när det är klart.
// 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;
}
},
});
Med async
och await
behöver du inte heller anropa återanropet context.done()
.
// 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}`);
}
Felsöka
Se felsökningsguiden för Node.js.
Nästa steg
Mer information finns i följande resurser: