本文讨论 Node.js 编程模型版本 3 和版本 4 之间的差异,以及如何升级现有 v3 应用。 如果要创建新的 v4 应用而不是升级现有 v3 应用,请参阅面向 Visual Studio Code (VS Code) 或 Azure Functions Core Tools 的教程。 本文使用“提示”提醒来突出显示升级应用时应采取的最重要的具体操作。 版本 4 旨在为 Node.js 开发人员提供以下权益:
- 为 Node.js 开发人员提供熟悉且直观的体验。
- 通过支持完全自定义,增强文件结构的灵活性。
- 切换到以代码为中心的方法来定义函数配置。
注意事项
注释
Node.js 编程模型的版本 4 目前为公共预览版。
- 在预览期间,v4 模型要求将应用设置 AzureWebJobsFeatureFlags设为EnableWorkerIndexing。 有关详细信息,请参阅启用 v4 编程模型。
- 不应将 Node.js“编程模型”与 Azure Functions“运行时”混淆。
- 编程模型:定义代码的创作方式,并特定于 JavaScript 和 TypeScript。
- 运行时:定义 Azure Functions 的基础行为,并在所有语言之间共享。
 
- 编程模型版本严格绑定到 @azure/functionsnpm 包的版本,并且独立于运行时进行版本控制。 运行时和编程模型都使用“4”作为其最新主版本,但这纯粹是巧合。
- 请记住,不能在同一函数应用中混用 v3 和 v4 编程模型。 在应用中注册一个 v4 函数后,function.json文件中注册的任何 v3 函数都将被忽略。
要求
Node.js 编程模型的版本 4 需要以下最低版本:
- 
              @azure/functionsnpm 包 v4.0.0
- Node.js v18+
- Azure Functions 运行时 v4.25+
- Azure Functions Core Tools v4.0.5382+(如果在本地运行)
- 
              @azure/functionsnpm 包 v4.0.0
- Node.js v18+
- TypeScript v4+
- Azure Functions 运行时 v4.25+
- Azure Functions Core Tools v4.0.5382+(如果在本地运行)
加入 npm 包
在 v4 中,@azure/functions npm 包中包含了支持 Node.js 编程模型的主要源代码。 在以前的版本中,该代码直接在 Azure 中提供,而 npm 包仅具有 TypeScript 类型。 现在,需要将此包加入 TypeScript 和 JavaScript 应用中。 你可以加入现有 v3 应用的包,但这不是必需的。
小窍门
确保 @azure/functions 包在 dependencies 文件的 devDependencies 部分(而不是 )中列出。 可以使用以下命令安装 v4:
npm install @azure/functions
设置应用入口点
在编程模型的 v4 中,可以根据需要构建代码。 在应用的根目录中,仅需要 host.json 和 package.json 文件。
否则,可以通过在 main 文件中设置  字段来定义文件结构。 可以使用 main将  字段设为单个文件或多个文件。 下表所示为 main 字段的示例值:
| 示例: | DESCRIPTION | 
|---|---|
| src/index.js | 从单个根文件注册函数。 | 
| src/functions/*.js | 从其自己的文件中注册每个函数。 | 
| src/{index.js,functions/*.js} | 从其自己的文件中注册每个函数的组合,但仍有一个常规应用级代码的根文件。 | 
| 示例: | DESCRIPTION | 
|---|---|
| dist/src/index.js | 从单个根文件注册函数。 | 
| dist/src/functions/*.js | 从其自己的文件中注册每个函数。 | 
| dist/src/{index.js,functions/*.js} | 从其自己的文件中注册每个函数的组合,但仍有一个常规应用级代码的根文件。 | 
小窍门
请确保在 main 文件中定义  字段。
切换参数的顺序
现在,触发器输入(而不是调用上下文)是函数处理程序的第一个参数。 调用上下文(现在是第二个参数)已在 v4 中简化,并且不像触发器输入一样必需。 如果不使用它,则可以将其禁用。
小窍门
切换参数的顺序。 例如,如果你使用的是 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 对象上的方法相对应。 例如,如果在 httpTrigger 中使用  类型,则可在代码中调用 app.http() 以注册函数。 如果使用 timerTrigger,则调用 app.timer()。
查看上下文的使用情况
在 v4 中,已对 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.req 或 context.bindings 来获取输入。
将主要输出设置为返回值
版本 4 仅支持一种通过返回值设置主输出的方法:
return { 
  body: `Hello, ${name}!` 
};
async function httpTrigger1(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
    // ...
    return { 
      body: `Hello, ${name}!` 
    };
}
小窍门
请确保始终在函数处理程序中返回输出,而不是使用 context 对象对其进行设置。
上下文日志记录
在 v4 中,日志记录方法已移动到根 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 核心中。
HTTP请求
- 正文。 可以使用特定于要接收的类型的方法来访问正文: - 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属性返回大多数类型,例如- string和- Buffer:- 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 故障排除指南。