دليل مطوري Azure Functions Node.js

هذا الدليل هو مقدمة لتطوير وظائف Azure باستخدام JavaScript أو TypeScript. تفترض المقالة أنك قرأت بالفعل دليل مطور Azure Functions.

هام

يتغير محتوى هذه المقالة استنادا إلى اختيارك لنموذج البرمجة Node.js في المحدد في أعلى هذه الصفحة. يجب أن يتطابق الإصدار الذي تختاره مع إصدار حزمة npm التي @azure/functions تستخدمها في تطبيقك. إذا لم يكن لديك تلك الحزمة مدرجة في ، package.jsonفإن الافتراضي هو v3. تعرف على المزيد حول الاختلافات بين v3 وv4 في دليل الترحيل.

بصفتك مطور Node.js، قد تكون مهتما أيضا بإحدى المقالات التالية:

الشروع في العمل المفاهيم التعلم الموجه

الاعتبارات

  • لا ينبغي الخلط بين نموذج البرمجة Node.js ووقت تشغيل Azure Functions:
    • نموذج البرمجة: يحدد كيفية تأليف التعليمات البرمجية الخاصة بك وهو خاص ب JavaScript وTypeScript.
    • وقت التشغيل: يحدد السلوك الأساسي ل Azure Functions ويتم مشاركته عبر جميع اللغات.
  • يرتبط إصدار نموذج البرمجة ارتباطا صارما بإصدار حزمة @azure/functions npm. يتم إصداره بشكل مستقل عن وقت التشغيل. يستخدم كل من وقت التشغيل ونموذج البرمجة الرقم 4 كإصدار رئيسي أحدث، ولكن هذه صدفة.
  • لا يمكنك خلط نماذج البرمجة v3 وv4 في نفس تطبيق الوظائف. بمجرد تسجيل وظيفة v4 واحدة في تطبيقك، يتم تجاهل أي وظائف v3 مسجلة في ملفات function.json .

الإصدارات المدعومة

يعرض الجدول التالي كل إصدار من نموذج برمجة Node.js جنبا إلى جنب مع إصداراته المدعومة من وقت تشغيل Azure Functions Node.js.

إصدار نموذج البرمجة مستوى الدعم إصدار وقت تشغيل الوظائف إصدار Node.js ‏‏الوصف
4.x التوفر العام 4.25+ 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.x، 8.x تم الوصول إلى انتهاء الدعم في 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/ لتجاهل إعداد المحرر، والاختبار/ لتجاهل حالات الاختبار، 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/: الموقع الافتراضي لجميع الدالات والمشغلات والروابط ذات الصلة.
  • اختبار/: (اختياري) يحتوي على حالات الاختبار لتطبيق الوظائف.
  • .funcignore: (اختياري) يعلن عن الملفات التي لا ينبغي نشرها إلى Azure. عادة ما يحتوي هذا الملف على .vscode/ لتجاهل إعداد المحرر، والاختبار/ لتجاهل حالات الاختبار، local.settings.json لمنع نشر إعدادات التطبيق المحلي.
  • host.json: يحتوي على خيارات التكوين التي تؤثر على جميع الوظائف في مثيل تطبيق الوظائف. لا يتم نشر هذا الملف في Azure. لا يتم دعم جميع الخيارات عند التشغيل محليًا. لمعرفة المزيد، راجع host.json.
  • local.settings.json: يستخدم لتخزين إعدادات التطبيق سلسلة الاتصال عند تشغيله محليا. لا يتم نشر هذا الملف في Azure. لمعرفة المزيد، راجع local.settings.file.
  • package.json: يحتوي على خيارات التكوين مثل قائمة تبعيات الحزمة ونقطة الإدخال الرئيسية والبرامج النصية.

تسجيل دالة

يسجل نموذج v3 دالة استنادا إلى وجود ملفين. أولا، تحتاج إلى 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 .package.json يمكنك تعيين 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، يتم دعم و binary فقط string (streamغير مدعوم)
  • بالنسبة لإدخالات HTTP، يتم تجاهل الخاصية dataType . بدلا من ذلك، استخدم خصائص على request الكائن للحصول على النص الأساسي بالتنسيق المطلوب. لمزيد من المعلومات، راجع طلب HTTP.

في المثال التالي لمشغل قائمة انتظار التخزين، النوع myQueueItem الافتراضي هو string، ولكن إذا قمت بتعيين dataType إلى binary، يتغير النوع إلى 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');
    }
};

دالتك مطلوبة للحصول على إدخال أساسي واحد بالضبط يسمى المشغل. قد يحتوي أيضا على مدخلات ثانوية، وإخراج أساسي يسمى إخراج الإرجاع، و/أو المخرجات الثانوية. يشار أيضا إلى المدخلات والمخرجات على أنها روابط خارج سياق نموذج البرمجة 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);
    }
});

المدخلات والمخرجات العامة

apptriggerتوفر الكائنات و 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!` };
    }
});

سياق استدعاء

يتم تمرير كل استدعاء للدالة الخاصة بك كائن استدعاء context ، ويستخدم لقراءة المدخلات، وتعيين المخرجات، والكتابة إلى السجلات، وقراءة بيانات التعريف المختلفة. في نموذج v3، كائن السياق هو دائما الوسيطة الأولى التي يتم تمريرها إلى المعالج الخاص بك.

يحتوي context الكائن على الخصائص التالية:

الخاصية ‏‏الوصف
invocationId معرف استدعاء الدالة الحالية.
executionContext راجع سياق التنفيذ.
bindings راجع الروابط.
bindingData بيانات التعريف حول إدخال المشغل لهذا الاستدعاء، وليس بما في ذلك القيمة نفسها. على سبيل المثال، يحتوي مشغل مركز الأحداث على enqueuedTimeUtc خاصية .
traceContext سياق التتبع الموزع. لمزيد من المعلومات، انظر Trace Context.
bindingDefinitions تكوين المدخلات والمخرجات الخاصة بك، كما هو محدد في function.json.
req راجع طلب HTTP.
res راجع استجابة HTTP.

context.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 أي شيء). بمجرد انتهاء الدالة الخاصة بك (بمعنى آخر، يحل الوعد الذي تم إرجاعه)، يعرف نموذج v3 أن وظيفتك قد انتهت.

module.exports = async function (context, request) {
    context.log("you don't need context.done or an awaited call")
};

يتم تمرير كل استدعاء للدالة الخاصة بك كائن استدعاء context ، مع معلومات حول استدعاءك والأساليب المستخدمة للتسجيل. في نموذج v4، 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. لمزيد من التحكم، يمكنك بدلا من ذلك استخدام Application Insights Node.js SDK لإرسال بيانات مخصصة إلى مثيل Application Insights الخاص بك.

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.

تستخدم HttpRequest مشغلات HTTP والإخطار على الويب والكائنات HttpResponse لتمثيل رسائل HTTP. تمثل الفئات مجموعة فرعية من معيار الإحضار، باستخدام حزمة Node.jsundici.

طلب 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 أو القيمة الخالية عند عدم تسجيل دخول أي مستخدم من هذا القبيل.
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 أو القيمة الخالية عند عدم تسجيل دخول أي مستخدم من هذا القبيل.
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[] (اختياري) ملفات تعريف ارتباط استجابة 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() تعيين رأس "نوع المحتوى".
send() تم إهمال هذا الأسلوب. يقوم بتعيين النص الأساسي والمكالمات context.done() للإشارة إلى انتهاء وظيفة المزامنة. ملاحظة: res.end() مدعوم أيضا ويفعل الشيء نفسه.
sendStatus() تم إهمال هذا الأسلوب. يقوم بتعيين رمز الحالة والمكالمات context.done() للإشارة إلى انتهاء وظيفة المزامنة.
json() تم إهمال هذا الأسلوب. يقوم بتعيين "نوع المحتوى" إلى "application/json"، وتعيين النص الأساسي، واستدعاءات context.done() للإشارة إلى انتهاء وظيفة المزامنة.

يمكن تعيين الاستجابة بعدة طرق:

  • كواجهة بسيطة مع النوع HttpResponseInit: هذا الخيار هو الطريقة الأكثر إيجازا لإعادة الاستجابات.

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

    تحتوي الواجهة HttpResponseInit على الخصائص التالية:

    الخاصية نوع ‏‏الوصف
    body BodyInit (اختياري) نص استجابة ArrayBufferHTTP كأحد أو AsyncIterable<Uint8Array>أو Blobأو FormDataأو Iterable<Uint8Array>أو . NodeJS.ArrayBufferViewstringURLSearchParamsnull
    jsonBody any (اختياري) نص استجابة HTTP قابل للتسلسل JSON. إذا تم تعيينها، يتم تجاهل الخاصية HttpResponseInit.body لصالح هذه الخاصية.
    status number (اختياري) رمز حالة استجابة HTTP. إذا لم يتم تعيين، يتم تعيين افتراضيا إلى 200.
    headers HeadersInit (اختياري) عناوين استجابة HTTP.
    cookies 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[] ملفات تعريف ارتباط استجابة HTTP.
    body ReadableStream | null النص الأساسي كتدفق قابل للقراءة.
    bodyUsed boolean قيمة منطقية تشير إلى ما إذا كان قد تمت قراءة النص بالفعل.

تدفقات HTTP

تدفقات HTTP هي ميزة تسهل معالجة البيانات الكبيرة، ودفق استجابات OpenAI، وتقديم محتوى ديناميكي، ودعم سيناريوهات HTTP الأساسية الأخرى. يتيح لك دفق الطلبات والاستجابات من نقاط نهاية HTTP في تطبيق الوظائف Node.js. استخدم تدفقات HTTP في السيناريوهات التي يتطلب فيها تطبيقك التبادل والتفاعل في الوقت الحقيقي بين العميل والخادم عبر HTTP. يمكنك أيضا استخدام تدفقات HTTP للحصول على أفضل أداء وموثوقية لتطبيقاتك عند استخدام HTTP.

هام

تدفقات HTTP غير مدعومة في نموذج v3. قم بالترقية إلى نموذج v4 لاستخدام ميزة تدفق HTTP.

تدعم الأنواع الموجودة HttpRequest و HttpResponse في نموذج البرمجة v4 بالفعل طرقا مختلفة للتعامل مع نص الرسالة، بما في ذلك كتدفق.

المتطلبات الأساسية

تمكين التدفقات

استخدم هذه الخطوات لتمكين تدفقات HTTP في تطبيق الوظائف في Azure وفي مشاريعك المحلية:

  1. إذا كنت تخطط لدفق كميات كبيرة من البيانات، فعدل FUNCTIONS_REQUEST_BODY_SIZE_LIMIT الإعداد في Azure. الحد الأقصى الافتراضي لحجم النص الأساسي المسموح به هو 104857600، والذي يحد من طلباتك إلى حجم ~100 ميغابايت.

  2. للتطوير المحلي، أضف FUNCTIONS_REQUEST_BODY_SIZE_LIMIT أيضا إلى ملف local.settings.json.

  3. أضف التعليمات البرمجية التالية إلى تطبيقك في أي ملف مضمن في حقلك الرئيسي.

    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 المشغلة التي تقوم ببث محتوى الملف كاستجابة لطلبات HTTP GET الواردة:

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()، والتي ترجع دائما النص الأساسي كسلسلة.

Hooks

الخطافات غير مدعومة في نموذج 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 الخطأ الذي تم طرحه بواسطة الدالة، أو خال/غير معرف إذا لم يكن هناك خطأ. تؤثر التغييرات على هذه القيمة على النتيجة الإجمالية للدالة.
invocationContext تم تمرير كائن سياق استدعاء إلى الدالة .
hookData المكان الموصى به لتخزين البيانات ومشاركتها بين الخطافات في نفس النطاق. يجب استخدام اسم خاصية فريد بحيث لا يتعارض مع بيانات الخطافات الأخرى.

خطافات التطبيق

يتم تنفيذ خطافات التطبيق مرة واحدة لكل مثيل لتطبيقك، إما أثناء بدء التشغيل في خطاف appStart أو أثناء الإنهاء في خطاف appTerminate . خطافات إنهاء التطبيق لها وقت محدود للتنفيذ ولا يتم تنفيذها في جميع السيناريوهات.

لا يدعم وقت تشغيل Azure Functions حاليا تسجيل السياق خارج استدعاء. استخدم حزمة Application Insights npm لتسجيل البيانات أثناء خطافات مستوى التطبيق.

يسجل المثال التالي خطافات التطبيق:

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. لمزيد من المعلومات، راجع كيف تعمل Consumption and Premium plans.

سلوك التحجيم هذا كافٍ للعديد من تطبيقات Node.js. بالنسبة إلى التطبيقات المرتبطة بـ CPU، يمكنك تحسين الأداء بشكل أكبر باستخدام عمليات عاملة متعددة اللغة. يمكنك زيادة عدد عمليات العامل لكل مضيف من الافتراضي 1 حتى 10 كحد أقصى باستخدام إعداد تطبيق FUNCTIONS_WORKER_PROCESS_COUNT . يحاول Azure Functions بعد ذلك توزيع استدعاءات الوظيفة المتزامنة عبر هذه العوامل بالتساوي. يقلل هذا السلوك من احتمالية أن تمنع الدالة كثيفة الاستخدام لوحدة المعالجة المركزية الوظائف الأخرى من التشغيل. ينطبق الإعداد على كل مضيف تقوم Azure Functions بإنشائه عند توسيع نطاق التطبيق الخاص بك لتلبية الطلب.

تحذير

FUNCTIONS_WORKER_PROCESS_COUNT استخدم الإعداد بحذر. يمكن أن تؤدي العمليات المتعددة التي تعمل في نفس المثيل إلى سلوك غير متوقع وزيادة أوقات تحميل الدالة. إذا كنت تستخدم هذا الإعداد، فمن المستحسن للغاية إزاحة هذه الجوانب السلبية عن طريق التشغيل من ملف حزمة.

إصدار Node

يمكنك مشاهدة الإصدار الحالي الذي يستخدمه وقت التشغيل عن طريق تسجيل process.version من أي وظيفة. راجع supported versions للحصول على قائمة بالإصدارات Node.js التي يدعمها كل نموذج برمجة.

إعداد إصدار Node

تعتمد الطريقة التي تقوم بها بترقية إصدار Node.js على نظام التشغيل الذي يتم تشغيل تطبيق الوظائف عليه.

عند التشغيل على Windows، يتم تعيين إصدار Node.js بواسطة WEBSITE_NODE_DEFAULT_VERSION إعداد التطبيق. يمكن تحديث هذا الإعداد إما باستخدام Azure CLI أو في مدخل Microsoft Azure.

لمزيد من المعلومات حول إصدارات Node.js، راجع الإصدارات المدعومة.

قبل ترقية إصدار Node.js، تأكد من تشغيل تطبيق الوظائف على أحدث إصدار من وقت تشغيل Azure Functions. إذا كنت بحاجة إلى ترقية إصدار وقت التشغيل، فشاهد ترحيل التطبيقات من الإصدار 3.x من Azure Functions إلى الإصدار 4.x.

قم بتشغيل الأمر Azure CLI az functionapp config appsettings set لتحديث الإصدار Node.js لتطبيق الوظائف الذي يعمل على Windows:

az functionapp config appsettings set  --settings WEBSITE_NODE_DEFAULT_VERSION=~20 \
 --name <FUNCTION_APP_NAME> --resource-group <RESOURCE_GROUP_NAME> 

يؤدي هذا إلى WEBSITE_NODE_DEFAULT_VERSION تعيين إعداد التطبيق لإصدار LTS المدعوم من ~20.

بعد إجراء التغييرات، يتم إعادة تشغيل تطبيق الوظائف. لمعرفة المزيد حول دعم الوظائف 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، يتيح لك تطبيق الوظائف تعيين إعدادات التطبيق واستخدامها، مثل سلسلة الاتصال الخدمة، ويعرض هذه الإعدادات كمتغيرات بيئة أثناء التنفيذ.

توجد عدة طرق يمكنك من خلالها إضافة إعدادات تطبيق الوظائف وتحديثها وحذفها:

تتطلب التغييرات في إعدادات تطبيق الوظائف إعادة تشغيل تطبيق الوظائف.

متغيرات بيئة العامل

هناك العديد من متغيرات بيئة الوظائف الخاصة Node.js:

languageWorkers__node__arguments

يسمح لك هذا الإعداد بتحديد وسيطات مخصصة عند بدء عملية Node.js. غالبا ما يتم استخدامه محليا لبدء تشغيل العامل في وضع التصحيح، ولكن يمكن استخدامه أيضا في Azure إذا كنت بحاجة إلى وسيطات مخصصة.

تحذير

إذا كان ذلك ممكنا، تجنب استخدام languageWorkers__node__arguments في Azure لأنه يمكن أن يكون له تأثير سلبي على أوقات البدء الباردة. بدلا من استخدام عمال تم تجهيزهم مسبقا، يجب أن يبدأ وقت التشغيل عامل جديد من الصفر باستخدام الوسيطات المخصصة.

logging__logLevel__Worker

يضبط هذا الإعداد مستوى السجل الافتراضي لسجلات العامل الخاصة 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.jsonscriptFile و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" ضمن Values في local.settings.json. تخبر الوسيطة --inspect Node.js بالاستماع لعميل تصحيح الأخطاء، على المنفذ 9229 بشكل افتراضي. لمزيد من المعلومات، راجع دليل تصحيح الأخطاء Node.js.

التوصيات

يصف هذا القسم العديد من الأنماط المؤثرة لتطبيقات Node.js التي نوصي باتباعها.

اختر خطط خدمة التطبيقات single-vCPU

عند إنشاء تطبيق وظيفة يستخدم خطة خدمة التطبيقات، نوصي بتحديد خطة single-vCPU بدلاً من خطة مع vCPUs متعددة. اليوم، تعمل الدالات Node.js الوظائف بشكل أكثر كفاءة على الأجهزة الظاهرية لوحدة المعالجة المركزية الظاهرية الأحادية، ولا ينتج عن استخدام أجهزة ظاهرية أكبر تحسينات الأداء المتوقعة. عند الضرورة، يمكنك التحجيم يدويًا عن طريق إضافة المزيد من مثيلات single-vCPU VM، أو يمكنك تمكين autoscale. لمزيد من المعلومات، راجع حساب مثيل المقياس يدويًا أو تلقائيًا.

تشغيل من ملف حزمة

عند تطوير 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 غير المتزامن مع دالة رد اتصال الخطأ الأول كمعلمة ثانية. تتسبب هذه التعليمة البرمجية في كلتا المشكلتين المذكورتين سابقا. يمكن أن يؤدي الاستثناء الذي لم يتم اكتشافه بشكل صريح في النطاق الصحيح إلى تعطل العملية بأكملها (المشكلة رقم 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 غير المتزامن مع دالة رد اتصال الخطأ الأول كمعلمة ثانية. تتسبب هذه التعليمة البرمجية في كلتا المشكلتين المذكورتين سابقا. يمكن أن يؤدي الاستثناء الذي لم يتم اكتشافه بشكل صريح في النطاق الصحيح إلى تعطل العملية بأكملها (المشكلة رقم 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 للمساعدة في تجنب هاتين المشكلتين. تم تحويل معظم واجهات برمجة التطبيقات في النظام البنائي Node.js لدعم الوعود في شكل ما. على سبيل المثال، بدءا من الإصدار 14، يوفر fs/promises Node.js واجهة برمجة تطبيقات لاستبدال 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.

الخطوات التالية

لمزيد من المعلومات، راجع الموارد التالية: