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. Egenskapen name som definieras i function.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 egenskapen name som definieras i function.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 i function.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.bindingsbindningen. 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 och binary (stream är inte)
  • För HTTP-indata ignoreras egenskapen dataType . Använd i stället egenskaper för request 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.setoch 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, inputoch 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 kan function.jsondu 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 anropar context.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, nulleller string.
    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 valfritt HttpResponseInit 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 (förhandsversion)

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.

HTTP-strömmar är för närvarande i förhandsversion.

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

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:

  1. 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 är 104857600, vilket begränsar dina begäranden till en storlek på ~100 MB.

  2. För lokal utveckling lägger du även till FUNCTIONS_REQUEST_BODY_SIZE_LIMIT i filen local.settings.json.

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

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 som request.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-portalen.

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.jsonscriptFile 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.jsonmyFirstFunction 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 runeller exporten med namnet index. I följande exempel anges entryPointfunction.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 asyncawait 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 awaitbehö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: