Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Это руководство содержит общие сведения о разработке Azure Functions с помощью JavaScript или TypeScript. В статье предполагается, что вы уже прочитали руководство разработчика Azure Functions.
Внимание
Содержимое этой статьи изменяется на основе выбранной модели программирования Node.js в селекторе в верхней части этой страницы. Выбранная версия должна соответствовать версии @azure/functions пакета npm, который вы используете в приложении. Если в вашем package.jsonсписке нет этого пакета, значение по умолчанию — версия 3. Узнайте больше о различиях между версиями 3 и 4 в руководстве по миграции.
Как разработчик Node.js, вы также можете быть заинтересованы в одной из следующих статей:
| Начало работы | Основные понятия | Обучение под руководством |
|---|---|---|
Рекомендации
- Модель программирования Node.js не следует путать с средой выполнения Azure Functions:
- Модель программирования: определяет способ разработки кода и зависит от JavaScript и TypeScript.
- Runtime: определяет базовое поведение Azure Functions и совместно используется на всех языках.
- Версия модели программирования строго привязана к версии
@azure/functionsпакета npm. Она версионируется независимо от среды выполнения. Среда выполнения и модель программирования используют номер 4 в качестве последней основной версии, но это совпадение. - Нельзя смешивать модели программирования версии 3 и версии 4 в одном приложении-функции. После регистрации одной функции версии 4 в приложении все функции версии 3, зарегистрированные в function.json файлах, игнорируются.
Поддерживаемые версии
В следующей таблице показана каждая версия модели программирования Node.js вместе со своими поддерживаемыми версиями среды выполнения Azure Functions и Node.js.
| Версия модели программирования | Уровень поддержки | Версия среды выполнения функций | версия Node.js | Описание |
|---|---|---|---|---|
| 4.x | Общедоступная версия | 4.25+ | 22.x 20.x, 18.x | Поддерживает гибкую структуру файлов и ориентированный на код подход к триггерам и привязкам. |
| 3.x | Общедоступная версия | 4.x | 20.x, 18.x, 16.x, 14.x | Требуется определенная структура файлов с триггерами и привязками, объявленными в файле "function.json" |
| 2.x | Н/Д | 3.x | 14.x, 12.x, 10.x | Поддержка завершена 13 декабря 2022 г. См. Версии функций для получения дополнительной информации. |
| 1.x | Н/Д | 2.x | 10,х, 8,х | Поддержка завершена 13 декабря 2022 г. См. Версии функций для получения дополнительной информации. |
Структура папок
Требуемая структура папок для проекта JavaScript выглядит следующим образом:
<project_root>/
| - .vscode/
| - node_modules/
| - myFirstFunction/
| | - index.js
| | - function.json
| - mySecondFunction/
| | - index.js
| | - function.json
| - .funcignore
| - host.json
| - local.settings.json
| - package.json
Основная папка проекта, <project_root>, может содержать следующие файлы:
- .vscode/: (необязательно) содержит хранимую конфигурацию Visual Studio Code. Чтобы узнать больше, см. параметры Visual Studio Code.
- myFirstFunction/function.json: содержит конфигурацию триггера, входных данных и выходных данных функции. Имя каталога определяет имя функции.
- myFirstFunction/index.js: хранит код функции. Чтобы изменить путь к файлу по умолчанию, используйте scriptFile.
- .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Обычно этот файл содержит .vscode/, чтобы игнорировать параметры редактора, test/, чтобы игнорировать тестовые случаи, и local.settings.json, чтобы предотвратить публикацию параметров локального приложения.
- host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
- local.settings.json. Используется для хранения параметров приложения и строк подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
- package.json. Содержит параметры конфигурации, такие как список зависимостей пакета, основная точка входа и скрипты.
Рекомендуемая структура папок для проекта JavaScript выглядит следующим образом:
<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
Основная папка проекта, <project_root>, может содержать следующие файлы:
- .vscode/: (необязательно) содержит хранимую конфигурацию Visual Studio Code. Дополнительные сведения см. в разделе параметры Visual Studio Code.
- src/functions/: расположение по умолчанию для всех функций и связанных с ними триггеров и привязок.
- test/: (необязательно) Содержит тестовые варианты приложения-функции.
- .funcignore: (необязательно) объявляет файлы, которые не должны публиковаться в Azure. Обычно этот файл содержит .vscode/, чтобы игнорировать параметры редактора, test/, чтобы игнорировать тестовые случаи, и local.settings.json, чтобы предотвратить публикацию параметров локального приложения.
- host.json: содержит параметры глобальной конфигурации, влияющие на все функции в экземпляре приложения-функции. Этот файл публикуется в Azure. При локальном запуске поддерживаются не все параметры. Дополнительные сведения см. в разделе host.json.
- local.settings.json. Используется для хранения параметров приложения и строк подключения при локальном запуске. Этот файл не публикуется в Azure. Дополнительные сведения см. в разделе local.settings.file.
- package.json. Содержит параметры конфигурации, такие как список зависимостей пакета, основная точка входа и скрипты.
Регистрация функции
Модель версии 3 регистрирует функцию на основе существования двух файлов. Во-первых, вам нужен файл, расположенный function.json в папке один уровень вниз от корневого каталога приложения. Во-вторых, вам нужен файл JavaScript, который экспортирует вашу функцию. По умолчанию модель ищет index.js файл в той же папке, что и ваша function.json. Если вы используете TypeScript, вы должны использовать свойство scriptFile в function.json для указания на скомпилированный файл JavaScript. Чтобы настроить расположение файла или имя экспорта функции, ознакомьтесь с настройкой точки входа функции.
**
Экспортируемая функция всегда должна быть объявлена как async function в модели v3. Вы можете экспортировать синхронную функцию, но затем необходимо вызвать context.done(), чтобы сигнализировать о завершении вашей функции; это является устаревшей практикой и не рекомендуется.
Функция передает вызов context в качестве первого аргумента и входные данные в качестве оставшихся аргументов.
В следующем примере показана простая функция, которая регистрирует, срабатывает ли она и отвечает с помощью 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!" };
};
Модель программирования загружает функции в зависимости от поля в вашей main модели. Вы можете установить поле main на один или несколько файлов, используя шаблон glob. В следующей таблице показаны примеры значений main для поля:
| Пример | Описание |
|---|---|
src/index.js |
Зарегистрируйте функции из одного корневого файла. |
src/functions/*.js |
Зарегистрируйте каждую функцию из собственного файла. |
src/{index.js,functions/*.js} |
Сочетание, в котором вы регистрируете каждую функцию из собственного файла, но у вас по-прежнему есть корневой файл для общего кода на уровне приложений. |
Чтобы зарегистрировать функцию, необходимо импортировать app объект из @azure/functions модуля npm и вызвать метод, характерный для типа триггера. Первый аргумент при регистрации функции — это имя функции. Второй аргумент — это объект, указывающий options конфигурацию для триггера, обработчика и любых других входных или выходных данных. В некоторых случаях, когда конфигурация триггера не требуется, обработчик можно передать непосредственно в качестве второго аргумента вместо объекта options.
Регистрация функции может выполняться из любого файла в проекте, если этот файл загружается (напрямую или косвенно) на основании поля main в файле package.json. Функция должна быть зарегистрирована в глобальной области, так как не удается зарегистрировать функции после запуска выполнения.
В следующем примере показана простая функция, которая регистрирует, срабатывает ли она и отвечает с помощью 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!" };
},
});
Входные и выходные данные
Ваша функция должна иметь ровно один основной вход, называемый триггером. Он также может иметь вторичные входные данные и /или выходные данные. Входные и выходные данные настраиваются в function.json файлах, а также называются привязками.
Входные данные
Входные данные — это привязки, для direction которых задано значение in. Основное различие между триггером и вторичными входными данными заключается в том, что type для триггера заканчивается на Trigger, например, тип blobTrigger по сравнению с типом blob. Большинство функций используют только триггер, и поддерживается не так много дополнительных типов входных данных.
Доступ к входным данным можно получить несколькими способами:
[Рекомендуется] В качестве аргументов, переданных функции: используйте аргументы в том же порядке, в который они определены
function.json. Свойствоname, определенное вfunction.json, не обязательно должно совпадать с именем аргумента, хотя мы рекомендуем это для удобства организации.module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
В качестве свойств
context.bindings: используйте ключ, соответствующий свойству, определенномуnameв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); };
Выходные данные
Выходные данные — это привязки с direction, установленными на out, и их можно задать несколькими способами:
[Рекомендуется для однократных выходных данных] Возвращает значение напрямую: если вы используете асинхронную функцию, вы можете вернуть это значение напрямую. Необходимо изменить свойство
nameвыходной привязки на$returnвfunction.json, как в следующем примере:{ "name": "$return", "type": "http", "direction": "out" }module.exports = async function (context, request) { return { body: "Hello, world!", }; };
[Рекомендуется для нескольких выходных данных] Возвращает объект, содержащий все выходные данные: если вы используете асинхронную функцию, вы можете вернуть объект со свойством, соответствующим имени каждой привязки в вашей
function.json. В следующем примере используются выходные привязки с именем httpResponse и 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, }; };
Задайте значения
context.bindingsв: если вы не используете асинхронную функцию или не хотите использовать предыдущие параметры, можно задать значения непосредственно вcontext.bindings, где ключ соответствует имени привязки. В следующем примере используются выходные привязки с именем httpResponse и 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; };
Тип данных привязки
Вы можете использовать свойство dataType для входной привязки, чтобы изменить тип ваших входных данных. Однако подход имеет некоторые ограничения:
- В Node.js поддерживаются только
stringиbinaryподдерживаются (streamне) - Для HTTP входных данных свойство
dataTypeигнорируется. Вместо этого используйте свойства объектаrequest, чтобы получить текст в нужном формате. Дополнительные сведения см. в http-запросе.
В следующем примере триггера очереди хранилища типом по умолчанию является , но если установить myQueueItem в значение string, тип изменяется на Node.js dataType.
{
"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");
}
};
Ваша функция должна иметь ровно один основной вход, называемый триггером. У него также могут быть вторичные входные данные, первичные выходные данные, называемые возвращаемыми выходными данными и /или вторичными выходными данными. Входные и выходные данные также называются привязками вне контекста модели программирования Node.js. До версии 4 модели эти привязки были настроены в function.json файлах.
Входные данные триггера
Триггер является единственным обязательным входным или выходным данным. Для большинства типов триггеров необходимо зарегистрировать функцию с помощью метода объекта app с именем типа триггера. Вы можете указать конфигурацию, определенную для триггера непосредственно в аргументе options . Например, триггер HTTP позволяет указать маршрут. Во время выполнения значение, соответствующее этому триггеру, передается в качестве первого аргумента обработчику.
const { app } = require('@azure/functions');
app.http('helloWorld1', {
route: 'hello/world',
handler: async (request, context) => {
...
}
});
Возвращаемые выходные данные
Возвращаемые выходные данные являются необязательными и в некоторых случаях настроены по умолчанию. Например, триггер HTTP, зарегистрированный с app.http помощью, настраивается для автоматического возврата выходных данных ответа HTTP. Для большинства типов выходных данных вы указываете конфигурацию возврата с помощью объекта options для аргумента output, экспортированного из модуля @azure/functions. Во время выполнения вы устанавливаете этот выходной результат, возвращая его из обработчика.
В следующем примере используется триггер таймера и очередь выхода на хранение:
const { app, output } = require('@azure/functions');
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: output.storageQueue({
connection: 'storage_APPSETTING',
...
}),
handler: (myTimer, context) => {
return { hello: 'world' }
}
});
Дополнительные входные и выходные данные
Помимо триггера и возврата, при регистрации функции можно указать дополнительные входные или выходные данные для options аргумента.
input и output объекты, экспортированные из модуля @azure/functions, предоставляют ориентированные на тип методы, чтобы помочь в построении конфигурации. Во время выполнения вы получаете или задаете значения с context.extraInputs.get или context.extraOutputs.set, и передаете исходный объект конфигурации в качестве первого аргумента.
Следующий пример — это функция, активируемая очередью хранилища, с дополнительным входным данным BLOB-объекта хранилища, которое копируется в дополнительные выходные данные BLOB-объекта хранилища. Сообщение очереди должно быть именем файла и заменяет {queueTrigger} его как скопированное имя большого двоичного объекта с помощью выражения привязки.
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);
},
});
Универсальные входные и выходные данные
Объекты app, trigger, input и output, экспортируемые модулем @azure/functions, предоставляют типовые методы для большинства типов. Для всех типов, которые не поддерживаются, предоставляется метод, generic позволяющий вручную указать конфигурацию. Этот generic метод можно также использовать, если вы хотите изменить параметры по умолчанию, предоставляемые типовым методом.
В следующем примере показана простая функция, активироваемая HTTP, с помощью универсальных методов вместо методов, относящихся к типу.
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!` };
},
});
Типы пакетов SDK
Теперь несколько расширений привязки позволяют работать непосредственно с типами Azure SDK.
хранилище BLOB-объектов Azure
Возможности привязок пакета SDK в Azure Functions позволяют работать непосредственно с типами пакета SDK для хранилища BLOB-объектов Azure, такими как BlobClient и ContainerClient вместо необработанных данных. Это обеспечивает полный доступ ко всем методам пакета SDK при работе с большими двоичными объектами.
Чтобы настроить проект для работы с типами SDK, выполните следующие действия.
-
@azure/functions-extensions-blobДобавьте пакетыpackage.jsonпредварительного просмотра расширений в файл в проекте, который должен включать по крайней мере следующие пакеты:
"dependencies": {
"@azure/functions": "4.7.2-preview",
"@azure/functions-extensions-blob": "0.2.0-preview"
},
- Добавьте
enableHttpStream: trueвapp.setupдля поддержки типов потокового вещания:
import { app } from '@azure/functions';
app.setup({
enableHttpStream: true,
});
В этом примере показано, как получить BlobClient как из триггера хранилища Blob, так и из привязки ввода для триггера HTTP.
import "@azure/functions-extensions-blob"; // This is the mandatory first import for SDK binding
import { StorageBlobClient } from "@azure/functions-extensions-blob";
import { app, InvocationContext } from "@azure/functions";
export async function storageBlobTrigger(
blobStorageClient: StorageBlobClient, // SDK binding provides this client
context: InvocationContext
): Promise<void> {
context.log(`Blob trigger processing: ${context.triggerMetadata.name}`);
// Access to full SDK capabilities
const blobProperties = await blobStorageClient.blobClient.getProperties();
context.log(`Blob size: ${blobProperties.contentLength}`);
// Download blob content
const downloadResponse = await blobStorageClient.blobClient.download();
context.log(`Content: ${downloadResponse}`);
}
// Register the function
app.storageBlob("storageBlobTrigger", {
path: "snippets/{name}",
connection: "AzureWebJobsStorage",
sdkBinding: true, // Enable SDK binding
handler: storageBlobTrigger,
});
В этом примере показано, как получить ContainerClient из входной привязки BLOB-объекта хранилища с помощью триггера HTTP:
import "@azure/functions-extensions-blob"; // This is the mandatory first import for SDK binding
import { StorageBlobClient } from "@azure/functions-extensions-blob";
import {
app,
HttpRequest,
HttpResponseInit,
input,
InvocationContext,
} from "@azure/functions";
const blobInput = input.storageBlob({
path: "snippets",
connection: "AzureWebJobsStorage",
sdkBinding: true,
});
export async function listBlobs(
request: HttpRequest,
context: InvocationContext
): Promise<HttpResponseInit> {
// Get input binding for a specific container
const storageBlobClient = context.extraInputs.get(
blobInput
) as StorageBlobClient;
// List all blobs in the container
const blobs = [];
for await (const blob of storageBlobClient.containerClient.listBlobsFlat()) {
blobs.push(blob.name);
}
return { jsonBody: { blobs } };
}
app.http("listBlobs", {
methods: ["GET"],
authLevel: "function",
extraInputs: [blobInput],
handler: listBlobs,
});
При работе с типами SDK следует учитывать следующие рекомендации.
- Всегда размещайте
import "@azure/functions-extensions-blob"первым в файлах, чтобы гарантировать выполнение побочных эффектов. - Задайте
sdkBinding: trueв конфигурации привязки. - Используйте соответствующий тип клиента для операции:
-
blobClientдля операций с одним BLOB -
containerClientдля операций с контейнером
-
- Обработка ошибок соответствующим образом с помощью
try/catchблоков - Для крупных операций с большими бинарными объектами следует рассмотреть использование потоковых методов, чтобы избежать проблем с памятью.
Для получения дополнительной информации ознакомьтесь с этими примерами привязок SDK Blob Storage для Node.js: дополнительные примеры, показывающие, как включить привязки SDK для BLOB-объектов в ваше функциональное приложение.
Azure Service Bus
В этом примере используется тип ПАКЕТА SDK ServiceBusReceivedMessage, полученный из ServiceBusMessageContext, предоставляемый триггером Service Bus:
import '@azure/functions-extensions-servicebus'; // Ensure the Service Bus extension is imported
import { app, InvocationContext } from '@azure/functions';
import { ServiceBusMessageContext, messageBodyAsJson } from '@azure/functions-extensions-servicebus';
// This sample uses sdkBinding = true with manual message completion.
// With v0.4.0, message.body is returned as a raw Buffer instead of auto-parsed object.
export async function serviceBusQueueTrigger(
serviceBusMessageContext: ServiceBusMessageContext,
context: InvocationContext
): Promise<void> {
const message = serviceBusMessageContext.messages[0];
// v0.4.0: message.body is a Buffer — use messageBodyAsJson<T>() from the extension for one-line parsing
const bodyData = messageBodyAsJson(message);
context.log('Parsed message body:', bodyData);
// Get current retry count from custom properties, default to 0
const currentRetryCount = message.applicationProperties?.retryCnt
? parseInt(message.applicationProperties.retryCnt as string)
: 0;
context.log(`Current retry count: ${currentRetryCount}`);
if (currentRetryCount >= 3) {
// After 3 retries, complete the message to remove it from the queue
context.log(`Maximum retry count (3) reached. Completing message to prevent infinite loop.`);
await serviceBusMessageContext.actions.complete(message);
context.log('Message completed after maximum retries');
} else {
// Abandon with updated retry count
const newRetryCount = currentRetryCount + 1;
const propertiesToModify = {
retryCnt: newRetryCount.toString(),
lastRetryTime: new Date().toISOString(),
errorMessage: 'Processing failed',
};
context.log(`Abandoning message with retry count: ${newRetryCount}`);
await serviceBusMessageContext.actions.abandon(message, propertiesToModify);
}
context.log('triggerMetadata: ', context.triggerMetadata);
}
app.serviceBusQueue('serviceBusQueueTrigger1', {
connection: 'ServiceBusConnection',
queueName: 'testqueue',
sdkBinding: true,
Для другого примера использования типов SDK см. пример с экспоненциальным откатом.
Контекст вызова
Каждый вызов функции передает объект вызова context , используемый для чтения входных данных, задания выходных данных, записи в журналы и чтения различных метаданных. В модели версии 3 объект контекста всегда является первым аргументом, переданным обработчику.
Объект context имеет следующие свойства.
| Свойство | Описание |
|---|---|
invocationId |
Идентификатор вызова текущей функции. |
executionContext |
См. контекст выполнения. |
bindings |
См. привязки. |
bindingData |
Метаданные о входных параметрах триггера для этого вызова, за исключением самого значения. Например, триггер концентратора событий имеет enqueuedTimeUtc свойство. |
traceContext |
Контекст распределенной трассировки. Дополнительные сведения см. в разделе Trace Context. |
bindingDefinitions |
Конфигурация входных и выходных данных, как определено в function.json. |
req |
См . HTTP-запрос. |
res |
См HTTP-ответ. |
контекст.executionContext
Объект context.executionContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
invocationId |
Идентификатор вызова текущей функции. |
functionName |
Имя вызываемой функции. Имя папки, function.json содержащей файл, определяет имя функции. |
functionDirectory |
Папка, содержащая function.json файл. |
retryContext |
См. контекст повторных попыток. |
context.executionContext.retryContext
Объект context.executionContext.retryContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
retryCount |
Число, представляющее текущую попытку повтора. |
maxRetryCount |
Максимальное количество повторных попыток выполнения. Значение -1 указывает на неограниченное число повторных попыток. |
exception |
Исключение, вызвавшее повторную попытку. |
Объект context.bindings
Объект context.bindings используется для чтения входных данных или задания выходных данных. В следующем примере показан триггер очереди хранения, который используется context.bindings для копирования входного блоба хранилища в выходной блоб хранилища. Содержимое сообщения очереди заменяет {queueTrigger}, которое используется как имя файла, подлежащее копированию, с помощью выражения привязки.
{
"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
Метод context.done не рекомендуется. Перед поддержкой асинхронных функций вы сигнализируете, что функция выполняется путем вызова context.done():
module.exports = function (context, request) {
context.log("this pattern is now deprecated");
context.done();
};
Рекомендуется удалить вызов context.done() и пометить функцию как асинхронную, чтобы она возвращала обещание (даже если вы ничего не await сделали). Как только функция завершится (другими словами, возвращенное обещание разрешается), модель версии 3 знает, что ваша функция выполнена.
module.exports = async function (context, request) {
context.log("you don't need context.done or an awaited call");
};
Каждому вызову вашей функции передается объект вызова context, содержащий информацию о вызове и методах, используемых для ведения журнала. В модели версии 4 объект context обычно является вторым аргументом, переданным вашему обработчику.
Класс InvocationContext имеет следующие свойства:
| Свойство | Описание |
|---|---|
invocationId |
Идентификатор вызова текущей функции. |
functionName |
Имя функции. |
extraInputs |
Используется для получения значений дополнительных входных данных. Дополнительные сведения см. в дополнительных входных данных и выходных данных. |
extraOutputs |
Используется для задания значений дополнительных выходных данных. Дополнительные сведения см. в дополнительных входных данных и выходных данных. |
retryContext |
См. контекст повторных попыток. |
traceContext |
Контекст распределенной трассировки. Дополнительные сведения см. в разделе Trace Context. |
triggerMetadata |
Метаданные о входных параметрах триггера для этого вызова, за исключением самого значения. Например, триггер концентратора событий имеет enqueuedTimeUtc свойство. |
options |
Параметры, используемые при регистрации функции, после их проверки и с явно заданными значениями по умолчанию. |
Контекст повторной попытки
Объект retryContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
retryCount |
Число, представляющее текущую попытку повтора. |
maxRetryCount |
Максимальное количество повторных попыток выполнения. Значение -1 указывает на неограниченное число повторных попыток. |
exception |
Исключение, вызвавшее повторную попытку. |
Дополнительные сведения см. в разделе retry-policies.
Ведение журнала
В Azure Functions рекомендуется использовать context.log() для записи журналов. Azure Functions интегрируется с Azure Application Insights, чтобы лучше записывать журналы приложений-функций. Application Insights, часть Azure Monitor, предоставляет средства для сбора, визуализации и анализа как журналов приложений, так и трассировочных данных. Дополнительные сведения см. в статье monitoring Azure Functions.
Примечание.
Если вы используете альтернативный метод Node.js console.log , эти журналы отслеживаются на уровне приложения и не будут связаны с какой-либо конкретной функцией. Мы настоятельно рекомендуем использовать context для ведения журнала вместо console того, чтобы все журналы были связаны с определенной функцией.
В следующем примере записывается журнал на уровне сведений по умолчанию, включая идентификатор вызова:
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);
Уровни журнала
Помимо метода по умолчанию context.log доступны следующие методы, которые позволяют записывать журналы на определенных уровнях:
| Метод | Описание |
|---|---|
context.log.error() |
Записывает событие уровня ошибки в журналы. |
context.log.warn() |
Записывает событие уровня предупреждения в журналы. |
context.log.info() |
Записывает событие уровня информации в журналы. |
context.log.verbose() |
Записывает событие уровня трассировки в журналы. |
| Метод | Описание |
|---|---|
context.trace() |
Записывает событие уровня трассировки в журналы. |
context.debug() |
Записывает событие уровня отладки в журналы. |
context.info() |
Записывает событие уровня информации в журналы. |
context.warn() |
Записывает событие уровня предупреждения в журналы. |
context.error() |
Записывает событие уровня ошибки в журналы. |
Настройка уровня журнала
Azure Functions позволяет определить пороговый уровень, используемый при отслеживании и просмотре журналов. Чтобы задать пороговое значение, используйте logging.logLevel свойство в host.json файле. Это свойство позволяет определить уровень по умолчанию, применяемый ко всем функциям, или пороговое значение для каждой отдельной функции. Дополнительные сведения см. в статье Как настроить мониторинг для Azure Functions.
Отслеживание настраиваемых данных
По умолчанию Azure Functions записывает выходные данные в Application Insights в виде трассировок. Для большего контроля можно использовать SDK для Application Insights Node.js для отправки пользовательских журналов, метрик и зависимостей в ваш экземпляр Application Insights.
Примечание.
Методы в пакете SDK Node.js Application Insights могут изменяться с течением времени. В примерах, показанных здесь, могут быть незначительные отличия синтаксиса. Последние примеры использования API см. в документации по пакету SDK для Application Insights Node.js.
Для распределенной трассировки в модели программирования Node.js версии 4 можно использовать @azure/functions-opentelemetry-instrumentation пакет вместо пакета SDK Application Insights. Этот пакет предоставляет автоматическое инструментирование на основе OpenTelemetry для Azure Functions. Для получения дополнительных сведений см. репозиторий GitHub OpenTelemetry Azure Functions Instrumentation для Node.js.
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,
});
};
Параметр tagOverrides присваивает параметру operation_Id значение идентификатора вызова функции. Этот параметр позволяет сопоставлять все автоматически созданные и настраиваемые журналы для вызова данной функции.
Триггеры HTTP
Триггеры HTTP и веб-хук используют объекты запроса и ответа для представления HTTP-сообщений.
Триггеры HTTP и веб-перехватчика используют объекты HttpRequest и HttpResponse для представления HTTP-сообщений. Классы представляют подмножество стандарта fetch, с использованием пакета Node.js .
HTTP-запрос
Доступ к запросу можно получить несколькими способами:
В качестве второго аргумента функции:
module.exports = async function (context, request) { context.log(`Http function processed request for url "${request.url}"`);
Из
context.reqсвойства:module.exports = async function (context, request) { context.log(`Http function processed request for url "${context.req.url}"`);
Из именованных входных привязок: этот параметр работает так же, как любая привязка, не связанная с HTTP. Имя привязки в
function.jsonдолжно соответствовать ключу наcontext.bindings, или "request1" в следующем примере:{ "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}"`);
Объект HttpRequest имеет следующие свойства.
| Свойство | Тип | Описание |
|---|---|---|
method |
string |
Метод HTTP-запроса, используемый для вызова этой функции. |
url |
string |
URL-адрес запроса. |
headers |
Record<string, string> |
Заголовки HTTP-запроса. Этот объект чувствителен к регистру. Вместо этого рекомендуется использовать request.getHeader('header-name') без учета регистра. |
query |
Record<string, string> |
Запрос ключей и значений строковых параметров из URL-адреса. |
params |
Record<string, string> |
Ключи и значения параметров маршрута. |
user |
HttpRequestUser \| null |
Объект, представляющий пользователя, вошедшего в систему, через аутентификацию через Функции, аутентификацию через SWA или null, если пользователь не вошел в систему. |
body |
Buffer \| string \| any |
Если тип носителя — application/octet-stream или multipart/*, body это буфер. Если значение является строкой с возможностью синтаксического анализа JSON, body является объектом синтаксического анализа. В противном случае, это строка body. |
rawBody |
string |
Тело в виде строки. Несмотря на название, это свойство не возвращает буфер. |
bufferBody |
Buffer |
Тело в качестве буфера. |
Доступ к запросу можно получить, используя его в качестве первого аргумента в обработчике функции, вызванной HTTP.
async (request, context) => {
context.log(`Http function processed request for url "${request.url}"`);
Объект HttpRequest имеет следующие свойства.
| Свойство | Тип | Описание |
|---|---|---|
method |
string |
Метод HTTP-запроса, используемый для вызова этой функции. |
url |
string |
URL-адрес запроса. |
headers |
Headers |
Заголовки HTTP-запроса. |
query |
URLSearchParams |
Запрос ключей и значений строковых параметров из URL-адреса. |
params |
Record<string, string> |
Ключи и значения параметров маршрута. |
user |
HttpRequestUser \| null |
Объект, представляющий пользователя, вошедшего в систему, через аутентификацию через Функции, аутентификацию через SWA или null, если пользователь не вошел в систему. |
body |
ReadableStream \| null |
Тело в виде читаемого потока. |
bodyUsed |
boolean |
Логическое значение, указывающее, считывается ли текст. |
Чтобы получить доступ к тексту запроса или ответа, можно использовать следующие методы:
| Метод | Тип возвращаемых данных |
|---|---|
arrayBuffer() |
Promise<ArrayBuffer> |
blob() |
Promise<Blob> |
formData() |
Promise<FormData> |
json() |
Promise<unknown> |
text() |
Promise<string> |
Примечание.
Функции тела могут выполняться только один раз. Последующие вызовы разрешаются с помощью пустых строк или ArrayBuffers.
HTTP-ответ
Ответ можно задать несколькими способами:
context.resЗадайте свойство:module.exports = async function (context, request) { context.res = { body: `Hello, world!` };
Верните ответ: если ваша функция асинхронная и вы задаете имя привязки как
$returnв вашемfunction.json, вы можете вернуть ответ напрямую, вместо того чтобы задавать его вcontext.{ "type": "http", "direction": "out", "name": "$return" }module.exports = async function (context, request) { return { body: `Hello, world!` };
Задайте именованную выходную привязку: этот параметр работает так же, как любая привязка, не связанная с HTTP. Имя привязки в
function.jsonдолжно соответствовать ключу наcontext.bindings, или "response1" в следующем примере:{ "type": "http", "direction": "out", "name": "response1" }module.exports = async function (context, request) { context.bindings.response1 = { body: `Hello, world!` };
Вызов
context.res.send(): этот параметр не рекомендуется. Он неявно вызываетcontext.done()и не может использоваться в асинхронной функции.module.exports = function (context, request) { context.res.send(`Hello, world!`);
При создании нового объекта при настройке ответа этот объект должен соответствовать интерфейсу HttpResponseSimple , который имеет следующие свойства:
| Свойство | Тип | Описание |
|---|---|---|
headers |
Record<string, string> (необязательно) |
Заголовки HTTP-ответа. |
cookies |
Cookie[] (необязательно) |
Файлы cookie ответа HTTP. |
body |
any (необязательно) |
Текст ответа HTTP. |
statusCode |
number (необязательно) |
Код состояния HTTP-ответа. Если значение не задано, по умолчанию используется 200значение . |
status |
number (необязательно) |
То же самое, что statusCode. Это свойство игнорируется, если statusCode задано. |
Можно также изменить context.res объект, не перезаписав его. Объект по умолчанию context.res использует HttpResponseFull интерфейс, который поддерживает следующие методы в дополнение к свойствам HttpResponseSimple :
| Метод | Описание |
|---|---|
status() |
Устанавливает статус. |
setHeader() |
Задает поле заголовка. ПРИМЕЧАНИЕ. res.set() и res.header() также поддерживаются и выполняют те же функции. |
getHeader() |
Получите поле заголовка. ПРИМЕЧАНИЕ. res.get() Также поддерживается и выполняет то же самое. |
removeHeader() |
Удаляет заголовок. |
type() |
Задает заголовок content-type. |
send() |
Этот метод является устаревшим. Он задает тело и вызывает context.done(), чтобы указать на завершение функции синхронизации. ПРИМЕЧАНИЕ. res.end() Также поддерживается и выполняет то же самое. |
sendStatus() |
Этот метод является устаревшим. Он задает код состояния и вызовы context.done() для указания завершения функции синхронизации. |
json() |
Этот метод является устаревшим. Он устанавливает "content-type" на "application/json", устанавливает тело и вызывает context.done() для указания завершения функции синхронизации. |
Ответ можно задать несколькими способами:
Как простой интерфейс с типом
HttpResponseInit: этот параметр является наиболее кратким способом возврата ответов.return { body: `Hello, world!` };
Интерфейс HttpResponseInit имеет следующие свойства:
| Свойство | Тип | Описание |
|---|---|---|
body |
BodyInit (необязательно) |
Текст ответа HTTP в виде одного из ArrayBuffer, AsyncIterable<Uint8Array>BlobFormDataIterable<Uint8Array>NodeJS.ArrayBufferViewURLSearchParamsnullили .string |
jsonBody |
any (необязательно) |
Текст ответа HTTP, сериализуемый в формате JSON. Если задано, HttpResponseInit.body свойство игнорируется в пользу этого свойства. |
status |
number (необязательно) |
Код состояния HTTP-ответа. Если значение не задано, по умолчанию используется 200значение . |
headers |
HeadersInit (необязательно) |
Заголовки HTTP-ответа. |
cookies |
Cookie[] (необязательно) |
Файлы cookie ответа HTTP. |
Как класс с типом
HttpResponse: этот параметр предоставляет вспомогательные методы для чтения и изменения различных частей ответа, таких как заголовки.const response = new HttpResponse({ body: `Hello, world!` }); response.headers.set("content-type", "application/json"); return response;
Класс HttpResponse принимает необязательный HttpResponseInit аргумент в качестве аргумента его конструктора и имеет следующие свойства:
| Свойство | Тип | Описание |
|---|---|---|
status |
number |
Код состояния HTTP-ответа. |
headers |
Headers |
Заголовки HTTP-ответа. |
cookies |
Cookie[] |
Файлы cookie ответа HTTP. |
body |
ReadableStream | null |
Тело в виде читаемого потока. |
bodyUsed |
boolean |
Логическое значение, указывающее, было ли содержимое уже прочитано. |
HTTP-потоки
HTTP-потоки — это функция, которая упрощает обработку больших данных, потоковую передачу ответов OpenAI, доставку динамического содержимого и поддержку других основных сценариев HTTP. Он позволяет передавать запросы и ответы от конечных точек HTTP в приложении-функции Node.js. Используйте http-потоки в сценариях, когда приложению требуется обмен данными в режиме реального времени и взаимодействие между клиентом и сервером по протоколу HTTP. Вы также можете использовать HTTP-потоки для получения оптимальной производительности и надежности приложений при использовании HTTP.
Внимание
Http-потоки не поддерживаются в модели версии 3.
Обновите модель версии 4 , чтобы использовать функцию потоковой передачи HTTP.
Существующие HttpRequest и HttpResponse типы в модели программирования версии 4 уже поддерживают различные способы обработки текста сообщения, включая поток.
Предварительные требования
-
@azure/functionsnpm-пакет версии 4.3.0 или более поздней. - среда выполнения Azure Functions версии 4.28 или более поздней.
- Azure Functions Core Tools версии 4.0.5530 или более поздней версии, содержащей правильную версию среды выполнения.
Включение потоков
Выполните следующие действия, чтобы включить HTTP-потоки в приложении-функции в Azure и в локальных проектах:
Если планируется потоковая передача больших объемов данных, измените параметр
FUNCTIONS_REQUEST_BODY_SIZE_LIMITв Azure. Максимально допустимый по умолчанию размер тела запроса составляет104857600, что ограничивает ваши запросы размером примерно в 100 МБ.Для
FUNCTIONS_REQUEST_BODY_SIZE_LIMITтакже добавьте в файл local.settings.json.Добавьте следующий код в ваше приложение в любой файл, включенный вашим главным полем.
const { app } = require("@azure/functions"); app.setup({ enableHttpStream: true });
Примеры потоков
В этом примере показана HTTP-триггерная функция, которая получает данные через HTTP-запрос POST, а функция передает эти данные в потоке в указанный выходной файл.
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!' };
},
});
В этом примере показана HTTP-триггерная функция, которая передает содержимое файла в качестве ответа на входящие GET HTTP-запросы.
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 };
},
});
Пример приложения, готового к выполнению с помощью потоков, см. в этом примере в GitHub.
Соображения по потокам
- Используйте
request.body, чтобы достичь максимальной выгоды от потоков. Вы по-прежнему можете использовать такие методыrequest.text(), как , которые всегда возвращают текст в виде строки.
Хуки
Хуки не поддерживаются в модели версии v3. Обновите до модели v4, чтобы использовать хуки.
Используйте хук для выполнения кода в разных точках жизненного цикла Azure Functions. Хуки выполняются в порядке их регистрации и могут быть зарегистрированы из любого файла в вашем приложении. В настоящее время существуют две области применения хуков: "уровень приложения" и "уровень вызова".
Крючки вызова
Перехватчики вызовов выполняются один раз при каждом вызове вашей функции, либо до в перехватчике preInvocation, либо после в перехватчике postInvocation. По умолчанию ваш перехватчик выполняется для всех типов триггеров, но вы также можете фильтровать его по конкретным типам. В следующем примере показано, как зарегистрировать перехватчик вызовов и отфильтровать по типу триггера.
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}`
);
}
});
Первым аргументом обработчика хука является объект контекста, характерный для данного типа хуков.
Объект PreInvocationContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
inputs |
Аргументы, переданные вызову. |
functionHandler |
Обработчик функции для вызова. Изменения этого значения влияют на саму функцию. |
invocationContext |
Объект контекста вызова, переданный функции. |
hookData |
Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Следует использовать уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков. |
Объект PostInvocationContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
inputs |
Аргументы, переданные вызову. |
result |
Результат функции. Изменения этого значения влияют на общий результат функции. |
error |
Ошибка, выбрасываемая функцией, или null/undefined, если ошибка отсутствует. Изменения этого значения влияют на общий результат функции. |
invocationContext |
Объект контекста вызова, переданный функции. |
hookData |
Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Следует использовать уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков. |
Перехватчики приложений
Хуки приложения выполняются один раз для экземпляра вашего приложения, при запуске в хуке appStart или при завершении в хуке appTerminate. Перехватчики завершения приложения (хуки) имеют ограниченное время выполнения и могут не выполняться во всех сценариях.
Среда выполнения Azure Functions в настоящее время не поддерживает ведение журнала контекста за пределами вызова. Используйте пакет npm Application Insights для регистрации данных во время перехватчиков на уровне приложения.
В следующем примере регистрируются хуки приложений:
const { app } = require('@azure/functions');
app.hook.appStart((context) => {
// add your logic here
});
app.hook.appTerminate((context) => {
// add your logic here
});
Первым аргументом обработчика хука является объект контекста, характерный для данного типа хуков.
Объект AppStartContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
hookData |
Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Следует использовать уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков. |
Объект AppTerminateContext имеет следующие свойства.
| Свойство | Описание |
|---|---|
hookData |
Рекомендуемое место для хранения и совместного использования данных между перехватчиками в одной области. Следует использовать уникальное имя свойства, чтобы оно не конфликтовало с данными других хуков. |
Масштабирование и параллелизм
По умолчанию Azure Functions автоматически отслеживает нагрузку в приложении и создает больше экземпляров узлов для Node.js по мере необходимости. Azure Functions использует встроенные (не настраиваемые пользователем) пороговые значения для различных типов триггеров, чтобы решить, когда следует добавлять экземпляры, например возраст сообщений и размер очереди для QueueTrigger. Дополнительные сведения см. в статье, посвященной планам с оплатой по мере использования и планам "Премиум".
Такого поведения при масштабировании достаточно для многих приложений Node.js. Для приложений, зависящих от ЦП, производительность можно повысить путем увеличения числа рабочих процессов обработки языка. Число рабочих процессов на узел можно увеличить с 1 до максимума 10, используя параметр приложения FUNCTIONS_WORKER_PROCESS_COUNT. Затем Azure Functions пытается равномерно распределить одновременные вызовы функций между этими рабочими. Такое поведение делает его менее вероятным, что функция с большим объемом ЦП блокирует выполнение других функций. Этот параметр применяется к каждому узлу, который Azure Functions создает при масштабировании приложения в соответствии с требованиями.
Предупреждение
FUNCTIONS_WORKER_PROCESS_COUNT Используйте параметр с осторожностью. Несколько процессов, выполняемых в одном экземпляре, могут привести к непредсказуемому поведению и увеличению времени загрузки функции. При использовании этого параметра мы настоятельно рекомендуем компенсировать эти недостатки, запустив пакетный файл.
Версия Node.js
Чтобы увидеть текущую версию, которую использует среда выполнения, можно выполнить логирование process.version из любой функции. Список supported versions версий Node.js, поддерживаемых каждой моделью программирования.
Настройка версии Node.js
Способ обновления версии Node.js зависит от ОС, на которой работает ваше приложение-функция.
При запуске в Windows версия Node.js устанавливается параметром приложения WEBSITE_NODE_DEFAULT_VERSION. Этот параметр можно обновить с помощью Azure CLI или на портале Azure.
Дополнительные сведения о версиях Node.js см. в статье "Поддерживаемые версии".
Перед обновлением версии Node.js убедитесь, что приложение-функция работает в последней версии среды выполнения Azure Functions. Если вам нужно обновить версию среды выполнения, ознакомьтесь с приложениями Migrate с Azure Functions версии 3.x до версии 4.x.
Выполните команду Azure CLI az functionapp config appsettings set, чтобы обновить версию Node.js приложения-функции, запущенную в Windows:
az functionapp config appsettings set --settings WEBSITE_NODE_DEFAULT_VERSION=~22 \
--name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME>
Этот параметр задает WEBSITE_NODE_DEFAULT_VERSION для приложения поддерживаемую версию ~22LTS.
После внесения изменений приложение-функция перезапускается. Дополнительные сведения о поддержке функций для Node.js см. в политике поддержки среды выполнения языка.
Переменные среды
Переменные среды могут быть полезны для операционных секретов (строки подключения, ключи, конечные точки и т. д.) или параметров среды, таких как переменные профилирования. Переменные среды можно добавлять как в локальные, так и в облачные среды и получать к ним доступ через process.env в коде функции.
В следующем примере регистрируется WEBSITE_SITE_NAME переменная среды:
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"]}`);
}
В локальной среде разработки
При локальном запуске проект функций содержит local.settings.json файл, в котором хранятся переменные среды в объекте Values .
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
"CUSTOM_ENV_VAR_1": "hello",
"CUSTOM_ENV_VAR_2": "world"
}
}
В облачной среде Azure
При запуске в Azure приложение-функция позволяет задавать и использовать параметры Application, например строки подключения службы, и предоставляет эти параметры в качестве переменных среды во время выполнения.
Существует несколько способов для добавления, обновления и удаления параметров приложения-функции.
Изменения в настройках функционального приложения требуют его перезапуска.
Переменные рабочей среды
Существует несколько переменных среды Функций, относящихся к Node.js:
АргументыlanguageWorkersузла
Этот параметр позволяет указать настраиваемые аргументы при запуске процесса Node.js. Он чаще всего используется локально для запуска рабочей роли в режиме отладки, но также может использоваться в Azure если вам нужны пользовательские аргументы.
Предупреждение
По возможности избегайте использования languageWorkers__node__arguments в Azure, так как это может негативно повлиять на время холодного запуска. Вместо использования предварительно разогретых рабочих среда выполнения должна запустить нового работника с нуля с пользовательскими аргументами.
ЛогированиеlogLevelWorker
Этот параметр настраивает уровень журнала по умолчанию для логов работников, специфичных для Node.js. По умолчанию отображаются только журналы предупреждений или ошибок, но вы можете настроить это на information или debug, чтобы помочь диагностировать проблемы с работником Node.js. Дополнительные сведения см. в разделе Настройка уровней журнала.
Модули ECMAScript (предварительная версия)
Примечание.
Поскольку модули ECMAScript в настоящее время являются предварительной версией в Node.js 14 или более поздних версиях в Azure Functions.
Модули ECMAScript (модули ES) — это новая официальная стандартная система модулей для Node.js. Пока что в примерах кода в этой статье используется синтаксис CommonJS. При запуске Azure Functions в Node.js 14 или более поздней версии можно написать функции с помощью синтаксиса модулей ES.
Чтобы использовать в функции модули ES, переименуйте ее файл, заменив расширение на .mjs. Следующий пример файла index.mjs — это функция, активируемая через HTTP, которая использует синтаксис модулей ES для импорта библиотеки uuid и возвращает значение.
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,
});
Настройка точки входа функции
Свойства function.json, а именно scriptFile и entryPoint, позволяют настроить расположение и имя экспортированной функции. Свойство scriptFile требуется при использовании TypeScript и должно указывать на скомпилированный JavaScript.
С использованием scriptFile
По умолчанию функция JavaScript выполняется из файла index.js, который расположен в том же родительском каталоге, что и соответствующий файл function.json.
scriptFile можно использовать для получения структуры папок, которая выглядит следующим образом:
<project_root>/
| - node_modules/
| - myFirstFunction/
| | - function.json
| - lib/
| | - sayHello.js
| - host.json
| - package.json
Файл function.json для myFirstFunction должен включать свойство scriptFile, указывающее на файл с экспортированной функцией, которую нужно выполнить.
{
"scriptFile": "../lib/sayHello.js",
"bindings": [
...
]
}
С использованием entryPoint
В модели v3 функцию необходимо экспортировать с помощью module.exports, чтобы ее можно было обнаружить и запустить. По умолчанию функция, которая выполняется при вызове, является единственным экспортом из этого файла, экспортом с именем run, или экспортом с именем index. В следующем примере устанавливается entryPoint в function.json на настраиваемое значение "logHello":
{
"entryPoint": "logHello",
"bindings": [
...
]
}
async function logHello(context) {
context.log("Hello, world!");
}
module.exports = { logHello };
Локальная отладка
Мы рекомендуем использовать VS Code для локальной отладки, поскольку он автоматически запускает процесс Node.js в режиме отладки и автоматически подключается к этому процессу для вас. Дополнительные сведения см. в статье о локальном запуске функции.
Если вы используете другое средство для отладки или хотите запустить процесс Node.js в режиме отладки вручную, добавьте "languageWorkers__node__arguments": "--inspect" в Valueslocal.settings.json. Аргумент --inspect сообщает Node.js прослушивать отладочный клиент по умолчанию на порте 9229. Дополнительные сведения см. в руководстве по отладке Node.js.
Рекомендации
В этом разделе описывается несколько влияющих шаблонов для приложений Node.js, которые рекомендуется следовать.
Выбирайте планы службы приложений с одним vCPU
При создании функционального приложения, которое использует план службы App Service, мы советуем выбирать план с одним vCPU вместо плана с несколькими vCPU. В настоящее время функции Node.js работают более эффективно на виртуальных машинах с одним виртуальным ЦП, а использование больших виртуальных машин не обеспечивает ожидаемых улучшений производительности. При необходимости вы можете вручную увеличить масштаб, добавив больше экземпляров виртуальных машин с одним виртуальным процессором (vCPU), или включить автоматическое масштабирование. Дополнительные сведения см. в статье Масштабирование числа экземпляров вручную или автоматически.
Запуск из файла пакета
При разработке Azure Functions в бессерверной модели размещения холодные запуски являются реальностью. Холодный запуск обозначает первый запуск функции приложения после периода простоя, что требует больше времени на включение. Для приложений Node.js с большими деревьями зависимостей холодный старт может иметь значительное влияние. Чтобы ускорить процесс холодного запуска, по возможности выполняйте функции в виде файла пакета. Многие методы развертывания используют эту модель по умолчанию, но если вы испытываете длительный холодный старт, убедитесь, что вы работаете именно так.
Использование одного статического клиента
Если вы используете клиент для конкретной службы в приложении Azure Functions, не создавайте новый клиент с каждым вызовом функции, так как можно получить ограничения подключения. Вместо этого создайте в глобальной области один статический клиент. Дополнительные сведения см. в разделе управляемые подключения в Azure Functions.
Использование async и await
При написании Azure Functions в Node.jsследует писать код с помощью ключевых слов async и await. Использование в коде async и await вместо обратных вызовов или .then и .catch с обещаниями помогает избежать двух распространенных проблем:
- Возникновение неперехваченных исключений, которые приводят к аварийному завершению процесса Node.js, что может повлиять и на выполнение других функций.
- Непредвиденное поведение, например отсутствие журналов из
context.log, вызванное асинхронными вызовами, которые не ожидаются должным образом.
В следующем примере асинхронный метод fs.readFile вызывается с функцией обратного вызова error-first в качестве второго параметра. Этот код вызывает обе проблемы, упомянутые ранее. Исключение, которое намеренно не обработано в нужной области, может обрушить весь процесс (проблема №1). Возврат без обеспечения завершения обратного вызова означает, что http-ответ иногда имеет пустой текст (проблема 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 };
},
});
В следующем примере асинхронный метод fs.readFile вызывается с функцией обратного вызова error-first в качестве второго параметра. Этот код вызывает обе проблемы, упомянутые ранее. Исключение, которое намеренно не обработано в нужной области, может обрушить весь процесс (проблема №1). Вызов устаревшего context.done() метода вне области обратного вызова может сигнализировать о завершении функции перед чтением файла (проблема 2). В этом примере слишком ранний вызов context.done() приводит к отсутствию записей в журнале, начиная с 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();
};
async
await Используйте ключевые слова, чтобы избежать обоих этих проблем. Большинство API в экосистеме Node.js были преобразованы в поддержку обещаний в некоторой форме. Например, начиная с версии 14, Node.js предоставляет fs/promises API для замены API обратного fs вызова.
В следующем примере любые необработанные исключения, вызываемые во время выполнения функции, приводят к сбою только отдельного вызова, вызвавшего исключение. Ключевое await слово означает, что шаги, следующие за readFile, выполняются только после его завершения.
// 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;
}
},
});
С async и await также не требуется совершать обратный вызов 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}`);
};
Устранение неполадок
См. руководство по устранению неполадок Node.js.
Следующие шаги
Дополнительные сведения см. на следующих ресурсах:
- Лучшие практики для Azure Functions
- Справочник разработчика Azure Functions
- Azure Functions триггеры и привязки