移轉至適用於 Azure Functions 的第 4 版 Node.js 程式設計模型

本文討論 Node.js 程式設計模型第 3 版和第 4 版之間的差異,以及如何升級現有的第 3 版應用程式。 如果您想要建立新的第 4 版應用程式,而不是升級現有的第 3 版應用程式,請參閱 Visual Studio Code(VS Code)Azure Functions Core Tools 教學課程。 本文使用「提示」警示,來醒目提示升級應用程式時應採取的最重要具體動作。

第 4 版的設計目的是為 Node.js 開發人員提供下列優點:

  • 為 Node.js 開發人員提供熟悉且直覺的體驗。
  • 讓檔案結構變得更彈性,並支援完整自訂。
  • 切換至以程式碼為中心的方法來定義函式設定。

考量

  • 不應將 Node.js 程式設計模型與 Azure Functions 執行階段混淆:
    • 程式設計模型:定義您撰寫程式碼的方式,以及 JavaScript 和 TypeScript 特有的方式。
    • 執行階段:定義 Azure Functions 的基礎行為,並跨所有語言共用。
  • 程式設計模型的版本會嚴格地繫結至 @azure/functions npm 套件版本。 此為獨立於執行階段的版本。 執行階段和程式設計模型都使用數字 4 作為其最新的主要版本,但這是巧合。
  • 您無法在相同的函數應用程式中混合使用 v3 和 v4 程式設計模型。 一旦您在應用程式中註冊一個 v4 函式,function.json 檔案中註冊的任何 v3 函式就會遭到忽略。

需求

Node.js 程式設計模型的第 4 版需要下列最低版本:

安裝 npm 套件

在第 4 版中,@azure/functions npm 套件包含支援 Node.js 程式設計模型的主要原始程式碼。 在舊版中,該程式碼直接隨附於 Azure 中,而 npm 套件只有 TypeScript 類型。 您現在需要同時包含適用於 TypeScript 和 JavaScript 應用程式的此套件。 您可以包含現有第 3 版應用程式的套件,但不一定要這麼做。

提示

確保在 package.json 檔案中的 dependencies 區段 (而不是 devDependencies) 會列出 @azure/functions 套件。 您可以使用下列命令來安裝第 4 版:

npm install @azure/functions

設定應用程式進入點

在程式設計模型的第 4 版中,您可以視需要建構程式碼。 應用程式根目錄中唯一需要的檔案是 host.json 和 package.json

否則,您可以在 package.json 檔案中設定 main 欄位來定義檔案結構。 您可以使用 glob 模式,將 main 欄位設為單一檔案或多個檔案。 下表顯示 main 欄位的範例值:

範例 描述
src/index.js 從單一根檔案註冊函式。
src/functions/*.js 從自己的檔案註冊每個函式。
src/{index.js,functions/*.js} 組合可讓您從自己的檔案註冊每個函式,但您仍有一般應用層級程式碼的根檔案。
範例 描述
dist/src/index.js 從單一根檔案註冊函式。
dist/src/functions/*.js 從自己的檔案註冊每個函式。
dist/src/{index.js,functions/*.js} 組合可讓您從自己的檔案註冊每個函式,但您仍有一般應用層級程式碼的根檔案。

提示

請確定您在 package.json 檔案中定義 main 欄位。

切換引數的順序

觸發程序輸入 (而不是叫用內容) 現在是函式處理常式的第一個引數。 現在會在第 4 版中簡化第二個引數的叫用內容,而且不會像觸發程序輸入一樣需要該叫用內容。 如果不會用到該內容,則可以將其排除。

提示

切換引數的順序。 例如,如果您使用 HTTP 觸發程序,請將 (context, request) 切換至 (request, context),或是在不使用內容時就切換至 (request)

在程式碼中定義函式

您不再需要建立和維護這些個別的 function.json 設定檔。 您現在可以直接在 TypeScript 或 JavaScript 檔案中完整定義函式。 此外,許多屬性現在都有預設值,因此您不需要每次都得指定值。

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

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: async (request, context) => {
        context.log(`Http function processed request for url "${request.url}"`);

        const name = request.query.get('name') || (await request.text()) || 'world';

        return { body: `Hello, ${name}!` };
    },
});
import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';

export async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    context.log(`Http function processed request for url "${request.url}"`);

    const name = request.query.get('name') || (await request.text()) || 'world';

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

app.http('httpTrigger1', {
    methods: ['GET', 'POST'],
    authLevel: 'anonymous',
    handler: httpTrigger1,
});

提示

將設定從 function.json 檔案移至程式碼。 觸發程序的類別會對應至新模型中 app 物件上的方法。 例如,如果您在 function.json 中使用 httpTrigger 類別,請在程式碼中呼叫 app.http() 以註冊函式。 如果您使用 timerTrigger,請呼叫 app.timer()

檢閱內容的使用方式

在第 4 版中,context 物件會經過簡化以減少重複,並讓撰寫單元測試的過程變得更輕鬆。 例如,我們已簡化主要輸入和輸出,以便僅存取這些項目作為函式處理常式的引數和傳回值。

您無法再存取 context 物件上的主要輸入和輸出,但仍必須存取 context 物件上的次要輸入和輸出。 如需次要輸入和輸出的詳細資訊,請參閱 Node.js 開發人員指南

取得主要輸入作為引數

主要輸入也稱為觸發程序,而且是唯一必要的輸入或輸出。 您必須有一個 (且只有一個) 觸發程序。

第 4 版僅支援取得觸發程序輸入 (作為第一個引數) 的一種方式:

async function httpTrigger1(request, context) {
  const onlyOption = request;
async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
  const onlyOption = request;

提示

請確定您未使用 context.reqcontext.bindings 來取得輸入。

將主要輸出設定為傳回值

第 4 版僅支援透過傳回值設定主要輸出的一種方式:

return { 
  body: `Hello, ${name}!` 
};
async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    // ...
    return { 
      body: `Hello, ${name}!` 
    };
}

提示

請確定您一律會傳回函式處理常式中的輸出,而不是使用 context 物件來設定輸出。

內容記錄

如下列範例所示,在第 4 版中,記錄方法已移至根 context 物件。 如需記錄的詳細資訊,請參閱 Node.js 開發人員指南

context.log('This is an info log');
context.error('This is an error');
context.warn('This is an error');

建立測試內容

第 3 版不支援在 Azure Functions 執行階段外部建立叫用內容,因此單元測試的撰寫可能很困難。 第 4 版可讓您建立叫用內容的執行個體,除非您自行新增,否則測試期間的資訊並不詳細。

const testInvocationContext = new InvocationContext({
  functionName: 'testFunctionName',
  invocationId: 'testInvocationId'
});

檢閱 HTTP 類型的使用方式

HTTP 要求和回應類型現在是擷取標準的一部分。 這些類型對於 Azure Functions 不再是唯一的。

這些類型會在 Node.js 中使用 undici 套件。 此套件遵循擷取標準,目前已整合至 Node.js 核心。

HttpRequest

  • 本文。 您可以使用您要接收之類型的特定方法來存取主體:

    const body = await request.text();
    const body = await request.json();
    const body = await request.formData();
    const body = await request.arrayBuffer();
    const body = await request.blob();
    
  • 標頭:

    const header = request.headers.get('content-type');
    
  • 查詢參數

    const name = request.query.get('name');
    

HttpResponse

  • 狀態:

    return { status: 200 };
    
  • 本文

    使用 body 屬性可傳回大部分的類型,例如 stringBuffer

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

    使用 jsonBody 屬性,以最簡單的方式傳回 JSON 回應:

    return { jsonBody: { hello: "world" } };
    
  • 標頭。 視使用的 HttpResponse 類別或 HttpResponseInit 介面而定,您可以透過兩種方式來設定標頭:

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

提示

使用與新方法相符的 HTTP 要求或回應類型,來更新任何邏輯。

提示

使用與新方法相符的 HTTP 要求或回應類型,來更新任何邏輯。 您應該會收到 TypeScript 建置錯誤,以協助識別您是否使用舊方法。

疑難排解

請參閱 Node.js 疑難排解指南