مشاركة عبر


دليل دالات Azure Node.js المطورين

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

Important

يتغير محتوى هذه المقالة استنادا إلى اختيارك لنموذج البرمجة Node.js في المحدد في أعلى هذه الصفحة. يجب أن يتطابق الإصدار الذي تختاره مع إصدار حزمة npm التي تستخدمها في تطبيقك. إذا لم يكن لديك تلك الحزمة مدرجة في ، فإن الافتراضي هو v3. تعرف على مزيد من المعلومات عن الاختلافات بين الإصدار 3 والإصدار 4 في دليل الترحيل.

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

الشروع Concepts التعلم الموجه
  • دليل المطور
  • خيارات الاستضافة
  • اعتبارات الأداء
  • إنشاء تطبيقات بلا خادم
  • إعادة بناء Node.js وExpress APIs لـServerless APIs

Considerations

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

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

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

إصدار نموذج البرمجة مستوى الدعم إصدار وقت تشغيل الوظائف Node.js الإصدار Description
4.x GA 4.25+ 22.x 20.x ، 18.x يدعم بنية ملف مرنة ونهج يركز على التعليمات البرمجية للمشغلات والروابط.
3.x GA 4.x 20.x، 18.x، 16.x، 14.x يتطلب بنية ملف معينة مع المشغلات والروابط المعلن عنها في ملف "function.json"
2.x n/a 3.x 14.x، 12.x، 10.x تم الوصول إلى انتهاء الدعم في 13 ديسمبر 2022. راجع إصدارات الوظائف لمزيد من المعلومات.
1.x n/a 2.x 10.x، 8.x تم الوصول إلى انتهاء الدعم في 13 ديسمبر 2022. راجع إصدارات الوظائف لمزيد من المعلومات.

هيكل المجلد

  • JavaScript
  • TypeScript

تبدو بنية المجلد المطلوبة لمشروع 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 برمجية المخزن. لمعرفة المزيد، راجع تعليمة Visual Studio برمجية الإعدادات.
  • 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
  • TypeScript

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

تسجيل دالة

يسجل نموذج v3 دالة استنادا إلى وجود ملفين. أولا، تحتاج إلى ملف موجود في مجلد بمستوى واحد لأسفل من جذر تطبيقك. ثانيا ، تحتاج إلى ملف JavaScript يقوم بتصدير وظيفتك. بشكل افتراضي، يبحث النموذج عن ملف في نفس المجلد الخاص بك . إذا كنت تستخدم TypeScript، يجب استخدام الخاصية في للإشارة إلى ملف JavaScript المحول برمجيا. لتخصيص موقع الملف أو اسم التصدير للدالة، راجع تكوين نقطة إدخال الدالة.

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

يتم تمرير دالتك استدعاء كوسيطة أولى وإدخالاتك كوسيطات متبقية.

المثال التالي هو دالة بسيطة تسجل أنه تم تشغيلها وتستجيب مع :

  • JavaScript
  • TypeScript
{
  "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!" };
};

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

  • JavaScript
  • TypeScript
Example Description
src/index.js تسجيل الوظائف من ملف جذر واحد.
src/functions/*.js تسجيل كل دالة من ملفها الخاص.
src/{index.js,functions/*.js} تركيبة حيث تقوم بتسجيل كل وظيفة من ملفها الخاص، ولكن لا يزال لديك ملف جذر للتعليمات البرمجية العامة على مستوى التطبيق.

لتسجيل دالة، يجب استيراد الكائن من الوحدة النمطية npm واستدعاء الأسلوب الخاص بنوع المشغل الخاص بك. الوسيطة الأولى عند تسجيل دالة هي اسم الدالة. الوسيطة الثانية هي كائن يحدد تكوين المشغل والمعالج وأي مدخلات أو مخرجات أخرى. في بعض الحالات التي لا يكون فيها تكوين المشغل ضروريا، يمكنك تمرير المعالج مباشرة كوسيطة ثانية بدلا من كائن .

يمكن تسجيل دالة من أي ملف في مشروعك، طالما يتم تحميل هذا الملف (بشكل مباشر أو غير مباشر) استنادا إلى الحقل الموجود في الملف. يجب تسجيل الدالة في نطاق عمومي لأنه لا يمكنك تسجيل الوظائف بمجرد بدء عمليات التنفيذ.

المثال التالي هو دالة بسيطة تسجل أنه تم تشغيلها وتستجيب مع :

  • JavaScript
  • TypeScript
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!" };
  },
});

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

دالتك مطلوبة للحصول على إدخال أساسي واحد بالضبط يسمى المشغل. قد يكون لها أيضا مدخلات و/أو مخرجات ثانوية. يتم تكوين المدخلات والمخرجات في ملفاتك ويشار إليها أيضا باسم الروابط.

Inputs

المدخلات هي روابط مع تعيين إلى . الفرق الرئيسي بين المشغل والإدخل الثانوي هو أن لمشغل ينتهي في ، على سبيل المثال النوع مقابل النوع . تستخدم معظم الدالات مشغلا فقط، ولا يتم دعم العديد من أنواع الإدخال الثانوية.

يمكن الوصول إلى المدخلات بعدة طرق:

  • [مستحسن] كوسيطات تم تمريرها إلى الدالة: استخدم الوسيطات بالترتيب نفسه الذي تم تعريفها به في . لا تحتاج الخاصية المعرفة في إلى مطابقة اسم الوسيطة الخاصة بك، على الرغم من أننا نوصي بها من أجل المؤسسة.

    • JavaScript
    • TypeScript
    module.exports = async function (context, myTrigger, myInput, myOtherInput) { ... };
    

  • كخصائص : استخدم المفتاح المطابق للخاصية المحددة في .

    • JavaScript
    • TypeScript
    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);
    };
    

Outputs

المخرجات هي روابط مع تعيين إلى ويمكن تعيينها بعدة طرق:

  • [مستحسن للإخراج الفردي] إرجاع القيمة مباشرة: إذا كنت تستخدم دالة غير متزامنة، يمكنك إرجاع القيمة مباشرة. يجب تغيير خاصية ربط الإخراج إلى في مثل في المثال التالي:

    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      return {
        body: "Hello, world!",
      };
    };
    

  • [مستحسن لمخرجات متعددة] إرجاع كائن يحتوي على كافة المخرجات: إذا كنت تستخدم دالة غير متزامنة، يمكنك إرجاع كائن بخاصية مطابقة لاسم كل ربط في . يستخدم المثال التالي روابط الإخراج المسماة "httpResponse" و"queueOutput":

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      let message = "Hello, world!";
      return {
        httpResponse: {
          body: message,
        },
        queueOutput: message,
      };
    };
    

  • تعيين القيم على : إذا كنت لا تستخدم دالة غير متزامنة أو كنت لا تريد استخدام الخيارات السابقة، يمكنك تعيين القيم مباشرة على ، حيث يتطابق المفتاح مع اسم الربط. يستخدم المثال التالي روابط الإخراج المسماة "httpResponse" و"queueOutput":

    {
        "name": "httpResponse",
        "type": "http",
        "direction": "out"
    },
    {
        "name": "queueOutput",
        "type": "queue",
        "direction": "out",
        "queueName": "helloworldqueue",
        "connection": "storage_APPSETTING"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
      let message = "Hello, world!";
      context.bindings.httpResponse = {
        body: message,
      };
      context.bindings.queueOutput = message;
    };
    

نوع بيانات الربط

يمكنك استخدام الخاصية على ربط إدخال لتغيير نوع الإدخال الخاص بك. ومع ذلك، فإن النهج له بعض القيود:

  • في Node.js، يتم دعم و فقط (غير مدعوم)
  • بالنسبة لإدخالات HTTP، يتم تجاهل الخاصية . بدلا من ذلك، استخدم خصائص على الكائن للحصول على النص الأساسي بالتنسيق المطلوب. لمزيد من المعلومات، راجع طلب HTTP.

في المثال التالي لمشغل قائمة انتظار التخزين، النوع الافتراضي هو ، ولكن إذا قمت بتعيين إلى ، يتغير النوع إلى Node.js .

{
  "name": "myQueueItem",
  "type": "queueTrigger",
  "direction": "in",
  "queueName": "helloworldqueue",
  "connection": "storage_APPSETTING",
  "dataType": "binary"
}
  • JavaScript
  • TypeScript
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 من النموذج، تم تكوين هذه الروابط في الملفات.

إدخال الزناد

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

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

app.http('helloWorld1', {
    route: 'hello/world',
    handler: async (request, context) => {
        ...
    }
});

إخراج الإرجاع

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

يستخدم المثال التالي مشغل مؤقتوإخراج قائمة انتظار تخزين:

  • JavaScript
  • TypeScript
const { app, output } = require('@azure/functions');

app.timer('timerTrigger1', {
    schedule: '0 */5 * * * *',
    return: output.storageQueue({
        connection: 'storage_APPSETTING',
        ...
    }),
    handler: (myTimer, context) => {
        return { hello: 'world' }
    }
});

مدخلات ومخرجات إضافية

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

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

  • JavaScript
  • TypeScript
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);
  },
});

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

توفر الكائنات و و و التي تم تصديرها بواسطة الوحدة النمطية أساليب خاصة بالنوع لمعظم الأنواع. بالنسبة لجميع الأنواع غير المدعومة، يتم توفير أسلوب للسماح لك بتحديد التكوين يدويا. يمكن أيضا استخدام الأسلوب إذا كنت تريد تغيير الإعدادات الافتراضية التي يوفرها أسلوب خاص بنوع معين.

المثال التالي هو دالة HTTP بسيطة يتم تشغيلها باستخدام أساليب عامة بدلا من أساليب خاصة بالنوع.

  • JavaScript
  • TypeScript
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.

تخزين Azure Blob

قدرة ربط SDK في دالات Azure تتيح لك العمل مباشرة مع أنواع SDK لتخزين Blob Azure مثل BlobClient و ContainerClient بدلا من البيانات الخام. يوفر هذا وصولا كاملا إلى جميع أساليب SDK عند العمل مع الكائنات الثنائية كبيرة الحجم.

لتكوين مشروعك للعمل مع أنواع مجموعات تطوير البرمجيات:

  1. أضف حزم معاينة الامتداد إلى الملف في المشروع، والتي يجب أن تتضمن على الأقل هذه الحزم:
"dependencies": {
  "@azure/functions": "4.7.2-preview",
  "@azure/functions-extensions-blob": "0.2.0-preview"
},
  1. أضف إلى دعم أنواع البث:
import { app } from '@azure/functions';

app.setup({
    enableHttpStream: true,
});

يوضح هذا المثال كيفية الحصول على BlobClient من كل من مشغل Storage 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,
});

يوضح هذا المثال كيفية الحصول على من كل من ربط إدخال Storage 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:

  • دائما اجعل البداية في ملفاتك لضمان استمرار الآثار الجانبية.
  • ضبطها في تكوين الربط الخاص بك.
  • استخدم نوع العميل المناسب لعمليتك:
    • للعمليات على كتلة واحدة
    • للعمليات على حاوية
  • التعامل مع الأخطاء بشكل مناسب مع الكتل
  • بالنسبة لعمليات الكتل الكبيرة، فكر في استخدام طرق البث لتجنب مشاكل الذاكرة.

لمزيد من المعلومات، راجع هذه مخزن البيانات الثنائية الكبيرة تجلدات SDK ل Node.js Samples: لمزيد من الأمثلة حول كيفية دمج تقييدات SDK ل Blob في تطبيق الوظائف الخاص بك.

ناقل خدمة Azure

يستخدم هذا المثال نوع 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 } from '@azure/functions-extensions-servicebus';
import { parseBody } from '../servicebus-helpers'; // Interim helper until #50 lands

// 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 parseBody<T>() helper for one-line parsing
    const bodyData = parseBody(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',

لمثال آخر باستخدام أنواع SDK، انظر ><عينة استراتيجية التراجع الأسي .

سياق الاستدعاء

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

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

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

context.executionContext

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

Property Description
invocationId معرف استدعاء الدالة الحالية.
functionName اسم الدالة التي يتم استدعاؤها. يحدد اسم المجلد الذي يحتوي على الملف اسم الدالة.
functionDirectory المجلد الذي يحتوي على الملف.
retryContext راجع سياق إعادة المحاولة.

context.executionContext.retryContext

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

Property Description
retryCount رقم يمثل محاولة إعادة المحاولة الحالية.
maxRetryCount الحد الأقصى لعدد مرات إعادة محاولة تنفيذ. تعني قيمة إعادة المحاولة إلى أجل غير مسمى.
exception الاستثناء الذي تسبب في إعادة المحاولة.

context.bindings

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

{
    "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"
}
  • JavaScript
  • TypeScript
module.exports = async function (context, myQueueItem) {
  const blobValue = context.bindings.myInput;
  context.bindings.myOutput = blobValue;
};

context.done

الأسلوب مهمل. قبل دعم الدالات غير المتزامنة، يمكنك الإشارة إلى أن وظيفتك تتم عن طريق استدعاء :

  • JavaScript
  • TypeScript
module.exports = function (context, request) {
  context.log("this pattern is now deprecated");
  context.done();
};

نوصي بإزالة الاستدعاء ووضع علامة على الدالة على أنها غير متزامنة بحيث ترجع وعدا (حتى لو لم تكن أي شيء). بمجرد انتهاء الدالة الخاصة بك (بمعنى آخر، يحل الوعد الذي تم إرجاعه)، يعرف نموذج v3 أن وظيفتك قد انتهت.

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

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

تحتوي الفئة على الخصائص التالية:

Property Description
invocationId معرف استدعاء الدالة الحالية.
functionName اسم الدالة
extraInputs يستخدم للحصول على قيم المدخلات الإضافية. لمزيد من المعلومات، راجع المدخلات والمخرجات الإضافية.
extraOutputs يستخدم لتعيين قيم المخرجات الإضافية. لمزيد من المعلومات، راجع المدخلات والمخرجات الإضافية.
retryContext راجع سياق إعادة المحاولة.
traceContext سياق التتبع الموزع. لمزيد من المعلومات، انظر .
triggerMetadata بيانات التعريف حول إدخال المشغل لهذا الاستدعاء، وليس بما في ذلك القيمة نفسها. على سبيل المثال، يحتوي مشغل مركز الأحداث على خاصية .
options الخيارات المستخدمة عند تسجيل الدالة، بعد التحقق من صحتها وتحديد الإعدادات الافتراضية بشكل صريح.

سياق إعادة المحاولة

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

Property Description
retryCount رقم يمثل محاولة إعادة المحاولة الحالية.
maxRetryCount الحد الأقصى لعدد مرات إعادة محاولة تنفيذ. تعني قيمة إعادة المحاولة إلى أجل غير مسمى.
exception الاستثناء الذي تسبب في إعادة المحاولة.

لمزيد من المعلومات، انظر .

Logging

في دالات Azure، ينصح باستخدام context.log() لكتابة السجلات. دالات Azure يتكامل مع Azure Application Insights لالتقاط سجلات تطبيقات الوظائف بشكل أفضل. يوفر Application Insights، جزء من Azure Monitor، وسائل لجمع وعرض بصري وتحليل سجلات التطبيقات ومخرجات التتبع الخاصة بك. لمعرفة المزيد، راجع monitoring دالات Azure.

Note

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

يكتب المثال التالي سجلا على مستوى "المعلومات" الافتراضي، بما في ذلك معرف استدعاء:

  • JavaScript
  • TypeScript
context.log(`Something has happened. Invocation ID: "${context.invocationId}"`);

مستويات السجل

بالإضافة إلى الأسلوب الافتراضي ، تتوفر الطرق التالية التي تتيح لك كتابة السجلات على مستويات محددة:

Method Description
context.log.error() تكتب حدث على مستوى الخطأ على السجلات.
context.log.warn() تكتب حدث مستوى التحذير على السجلات.
context.log.info() كتابة حدث على مستوى المعلومات إلى السجلات.
context.log.verbose() يكتب حدثا على مستوى التتبع إلى السجلات.
Method Description
context.trace() يكتب حدثا على مستوى التتبع إلى السجلات.
context.debug() يكتب حدثا على مستوى تتبع الأخطاء إلى السجلات.
context.info() كتابة حدث على مستوى المعلومات إلى السجلات.
context.warn() تكتب حدث مستوى التحذير على السجلات.
context.error() تكتب حدث على مستوى الخطأ على السجلات.

تكوين مستوى السجل

يتيح لك دالات Azure تحديد مستوى العتبة الذي يجب استخدامه عند تتبع وعرض السجلات. لتعيين الحد، استخدم الخاصية في الملف. تتيح لك هذه الخاصية تحديد مستوى افتراضي مطبق على جميع الدالات، أو حد لكل دالة فردية. لمعرفة المزيد، راجع كيفية تكوين المراقبة ل دالات Azure.

تعقب البيانات المخصصة

بشكل افتراضي، يكتب دالات Azure الإخراج كتتبع إلى Application Insights. لمزيد من التحكم، يمكنك بدلا من ذلك استخدام Application Insights Node.js SDK لإرسال سجلات ومقاييس وتبعيات مخصصة إلى نسخة Application Insights الخاصة بك.

Note

قد تتغير الطرق في رؤى التطبيقات Node.js SDK مع مرور الوقت. قد تكون هناك اختلافات نحوية بسيطة من الأمثلة المعروضة هنا. للحصول على أحدث أمثلة استخدام واجهة برمجة التطبيقات، راجع وثائق Application Insights Node.js SDK.

للتتبع الموزع في نموذج البرمجة Node.js v4، يمكنك استخدام الحزمة بدلا من Application Insights SDK. توفر هذه الحزمة أجهزة تلقائية قائمة على OpenTelemetry لنظام دالات Azure. لمزيد من المعلومات، راجع OpenTelemetry دالات Azure Instrumentation لمستودع Node.js GitHub.

  • JavaScript
  • TypeScript
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,
  });
};

المعلمة تعين لمعرف استدعاء الوظيفة. يمكنك هذا الإعداد من ربط كافة السجلات التي تم إنشاؤها تلقائيا والسجلات المخصصة لاستدعاء دالة معينة.

مشغلات HTTP

تستخدم مشغلات HTTP والإخطار على الويب كائنات الطلب والاستجابة لتمثيل رسائل HTTP.

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

طلب HTTP

يمكن الوصول إلى الطلب بعدة طرق:

  • كوسيطة ثانية لدالتك:

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${request.url}"`);
    

  • من الخاصية :

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.req.url}"`);
    

  • من روابط الإدخال المسماة: يعمل هذا الخيار بنفس الطريقة التي يعمل بها أي ربط غير HTTP. يجب أن يتطابق اسم الربط في مع المفتاح الموجود على أو "request1" في المثال التالي:

    {
      "name": "request1",
      "type": "httpTrigger",
      "direction": "in",
      "authLevel": "anonymous",
      "methods": ["get", "post"]
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.log(`Http function processed request for url "${context.bindings.request1.url}"`);
    

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

Property Type Description
method string أسلوب طلب HTTP المستخدم لاستدعاء هذه الدالة.
url string طلب عنوان URL.
headers Record<string, string> عناوين طلب HTTP. هذا الكائن حساس لحالة الأحرف. يوصى باستخدام بدلا من ذلك، وهو غير حساس لحالة الأحرف.
query Record<string, string> مفاتيح وقيم معلمات سلسلة الاستعلام من عنوان URL.
params Record<string, string> مفاتيح وقيم معلمات المسار.
user HttpRequestUser \| null كائن يمثل المستخدم الذي قام بتسجيل الدخول، إما من خلال مصادقة الوظائف أو مصادقة SWA أو القيمة الخالية عند عدم تسجيل دخول أي مستخدم من هذا القبيل.
body Buffer \| string \| any إذا كان نوع الوسائط هو "application/octet-stream" أو "multipart/*"، فهو مخزن مؤقت. إذا كانت القيمة عبارة عن سلسلة قادرة على تحليل JSON، فهي الكائن الذي تم تحليله. خلاف ذلك، هو سلسلة.
rawBody string النص الأساسي كسلسلة. على الرغم من الاسم، لا ترجع هذه الخاصية مخزنا مؤقتا.
bufferBody Buffer النص الأساسي كمخزن مؤقت.

يمكن الوصول إلى الطلب كوسيطة أولى للمعالج الخاص بك لدالة HTTP التي تم تشغيلها.

  • JavaScript
  • TypeScript
async (request, context) => {
    context.log(`Http function processed request for url "${request.url}"`);

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

Property Type Description
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 قيمة منطقية تشير إلى ما إذا كان النص قد تمت قراءته بالفعل.

للوصول إلى نص طلب أو استجابة، يمكن استخدام الطرق التالية:

Method نوع الإرجاع
arrayBuffer() Promise<ArrayBuffer>
blob() Promise<Blob>
formData() Promise<FormData>
json() Promise<unknown>
text() Promise<string>

Note

يمكن تشغيل وظائف الجسم مرة واحدة فقط. يتم حل الاستدعاءات اللاحقة بسلاسل فارغة/ArrayBuffers.

استجابة HTTP

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

  • تعيين الخاصية :

    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.res = { body: `Hello, world!` };
    

  • إرجاع الاستجابة: إذا كانت الدالة غير متزامنة وقمت بتعيين اسم الربط إلى في ، يمكنك إرجاع الاستجابة مباشرة بدلا من تعيينها على .

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        return { body: `Hello, world!` };
    

  • تعيين ربط الإخراج المسمى: يعمل هذا الخيار بنفس الطريقة التي يعمل بها أي ربط غير HTTP. يجب أن يتطابق اسم الربط في مع المفتاح الموجود على أو "response1" في المثال التالي:

    {
      "type": "http",
      "direction": "out",
      "name": "response1"
    }
    
    • JavaScript
    • TypeScript
    module.exports = async function (context, request) {
        context.bindings.response1 = { body: `Hello, world!` };
    

  • استدعاء : تم إهمال هذا الخيار. يستدعي ضمنيا ولا يمكن استخدامه في دالة غير متزامنة.

    • JavaScript
    • TypeScript
    module.exports = function (context, request) {
        context.res.send(`Hello, world!`);
    

إذا قمت بإنشاء كائن جديد عند تعيين الاستجابة، يجب أن يتطابق هذا الكائن مع الواجهة ، التي تحتوي على الخصائص التالية:

Property Type Description
headers (اختياري) عناوين استجابة HTTP.
cookies (اختياري) ملفات تعريف ارتباط استجابة HTTP.
body (اختياري) نص استجابة HTTP.
statusCode (اختياري) رمز حالة استجابة HTTP. إذا لم يتم تعيين، يتم تعيين افتراضيا إلى .
status (اختياري) نفس . يتم تجاهل هذه الخاصية إذا تم تعيينها.

يمكنك أيضا تعديل الكائن دون الكتابة فوقه. يستخدم الكائن الافتراضي الواجهة التي تدعم الأساليب التالية بالإضافة إلى الخصائص :

Method Description
status() تعيين الحالة.
setHeader() تعيين حقل رأس. ملاحظة: كما أنها مدعومة وتفعل الشيء نفسه.
getHeader() الحصول على حقل رأس. ملاحظة: مدعوم أيضا ويفعل الشيء نفسه.
removeHeader() إزالة رأس.
type() تعيين رأس "نوع المحتوى".
send() تم إهمال هذا الأسلوب. يقوم بتعيين النص الأساسي والمكالمات للإشارة إلى انتهاء وظيفة المزامنة. ملاحظة: مدعوم أيضا ويفعل الشيء نفسه.
sendStatus() تم إهمال هذا الأسلوب. يقوم بتعيين رمز الحالة والمكالمات للإشارة إلى انتهاء وظيفة المزامنة.
json() تم إهمال هذا الأسلوب. يقوم بتعيين "نوع المحتوى" إلى "application/json"، وتعيين النص الأساسي، واستدعاءات للإشارة إلى انتهاء وظيفة المزامنة.

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

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

    • JavaScript
    • TypeScript
    return { body: `Hello, world!` };
    

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

Property Type Description
body (اختياري) نص استجابة HTTP كأحد أو أو أو أو أو .
jsonBody (اختياري) نص استجابة HTTP قابل للتسلسل JSON. إذا تم تعيينها، يتم تجاهل الخاصية لصالح هذه الخاصية.
status (اختياري) رمز حالة استجابة HTTP. إذا لم يتم تعيين، يتم تعيين افتراضيا إلى .
headers (اختياري) عناوين استجابة HTTP.
cookies (اختياري) ملفات تعريف ارتباط استجابة HTTP.
  • كفئة ذات نوع : يوفر هذا الخيار أساليب مساعدة لقراءة وتعديل أجزاء مختلفة من الاستجابة مثل الرؤوس.

    • JavaScript
    • TypeScript
    const response = new HttpResponse({ body: `Hello, world!` });
    response.headers.set("content-type", "application/json");
    return response;
    

تقبل الفئة اختياريا كوسيطة لمنشئها ولها الخصائص التالية:

Property Type Description
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.

Important

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

Prerequisites

  • إصدار حزمة npm 4.3.0 أو أحدث.
  • دالات Azure runtime الإصدار 4.28 أو أحدث.
  • دالات Azure Core Tools الإصدار 4.0.5530 أو إصدار أحدث، يحتوي على النسخة الصحيحة من وقت التشغيل.

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

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

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

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

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

    • JavaScript
    • TypeScript
    const { app } = require("@azure/functions");
    
    app.setup({ enableHttpStream: true });
    

أمثلة على الدفق

يوضح هذا المثال دالة مشغلة بواسطة HTTP تتلقى البيانات عبر طلب HTTP POST، وتبث الدالة هذه البيانات إلى ملف إخراج محدد:

  • JavaScript
  • TypeScript
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 الواردة:

  • JavaScript
  • TypeScript
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.

اعتبارات البث

  • استخدم للحصول على أقصى فائدة من استخدام التدفقات. لا يزال بإمكانك الاستمرار في استخدام أساليب مثل ، والتي ترجع دائما النص الأساسي كسلسلة.

Hooks

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

استخدم هوك لتنفيذ الكود في نقاط مختلفة من دورة حياة دالات Azure. يتم تنفيذ الخطافات بالترتيب الذي يتم تسجيلها به ويمكن تسجيلها من أي ملف في تطبيقك. هناك حاليا نطاقان من الخطافات، مستوى "التطبيق" ومستوى "استدعاء".

خطافات الاستدعاء

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

  • JavaScript
  • TypeScript
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}`
        );
    }
});

الوسيطة الأولى لمعالج الخطاف هي كائن سياق خاص بنوع الخطاف هذا.

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

Property Description
inputs تم تمرير الوسيطات إلى استدعاء .
functionHandler معالج الدالة للادعاء. تؤثر التغييرات التي تطرأ على هذه القيمة على الدالة نفسها.
invocationContext تم تمرير كائن سياق الاستدعاء إلى الدالة.
hookData المكان الموصى به لتخزين البيانات ومشاركتها بين الخطافات في نفس النطاق. يجب استخدام اسم خاصية فريد بحيث لا يتعارض مع بيانات الخطافات الأخرى.

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

Property Description
inputs تم تمرير الوسيطات إلى استدعاء .
result نتيجة الدالة. تؤثر التغييرات على هذه القيمة على النتيجة الإجمالية للدالة.
error الخطأ الذي تم طرحه بواسطة الدالة، أو خال/غير معرف إذا لم يكن هناك خطأ. تؤثر التغييرات على هذه القيمة على النتيجة الإجمالية للدالة.
invocationContext تم تمرير كائن سياق الاستدعاء إلى الدالة.
hookData المكان الموصى به لتخزين البيانات ومشاركتها بين الخطافات في نفس النطاق. يجب استخدام اسم خاصية فريد بحيث لا يتعارض مع بيانات الخطافات الأخرى.

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

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

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

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

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

app.hook.appStart((context) => {
    // add your logic here
});

app.hook.appTerminate((context) => {
    // add your logic here
});

الوسيطة الأولى لمعالج الخطاف هي كائن سياق خاص بنوع الخطاف هذا.

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

Property Description
hookData المكان الموصى به لتخزين البيانات ومشاركتها بين الخطافات في نفس النطاق. يجب استخدام اسم خاصية فريد بحيث لا يتعارض مع بيانات الخطافات الأخرى.

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

Property Description
hookData المكان الموصى به لتخزين البيانات ومشاركتها بين الخطافات في نفس النطاق. يجب استخدام اسم خاصية فريد بحيث لا يتعارض مع بيانات الخطافات الأخرى.

التحجيم والتزامن

بشكل افتراضي، دالات Azure تراقب تلقائيا الحمل على تطبيقك وتنشئ المزيد من مثيلات المضيف Node.js حسب الحاجة. يستخدم دالات Azure عتبات مدمجة (غير قابلة للتخصيص من قبل المستخدم) لأنواع المشغلات المختلفة لتحديد متى تضيف مثلات، مثل عمر الرسائل وحجم قائمة الانتظار في QueueTrigger. لمزيد من المعلومات، راجع كيف تعمل Consumption and Premium plans.

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

Warning

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

إصدار العقدة

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

إعداد إصدار Node

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

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

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

قبل ترقية النسخة Node.js الخاصة بك، تأكد من أن تطبيق الوظائف يعمل على أحدث إصدار من وقت تشغيل دالات Azure. إذا كنت بحاجة إلى ترقية إصدار وقت التشغيل الخاص بك، راجع ترحيل التطبيقات من الإصدار 3.x دالات Azure إلى الإصدار 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>

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

بعد إجراء التغييرات، يتم إعادة تشغيل تطبيق الوظائف. لمعرفة المزيد حول دعم الوظائف Node.js، راجع نهج دعم وقت تشغيل اللغة.

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

يمكن أن تكون متغيرات البيئة مفيدة للأسرار التشغيلية (سلسلة الاتصال والمفاتيح ونقاط النهاية وما إلى ذلك) أو الإعدادات البيئية مثل متغيرات جمع المعلومات. يمكنك إضافة متغيرات البيئة في كل من البيئات المحلية والسحابية والوصول إليها من خلال التعليمات البرمجية للوظيفة.

يسجل المثال التالي متغير البيئة:

  • JavaScript
  • TypeScript
module.exports = async function (context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
};
  • JavaScript
  • TypeScript
async function timerTrigger1(myTimer, context) {
  context.log(`WEBSITE_SITE_NAME: ${process.env["WEBSITE_SITE_NAME"]}`);
}

في بيئة التنمية المحلية

عند التشغيل محليا، يتضمن مشروع الوظائف ملفا، حيث تقوم بتخزين متغيرات البيئة في العنصر .

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "CUSTOM_ENV_VAR_1": "hello",
    "CUSTOM_ENV_VAR_2": "world"
  }
}

In Azure cloud environment

عند تشغيل Azure، يتيح لك تطبيق الوظائف تعيين واستخدام إعدادات التطبيق، مثل سلاسل اتصال الخدمة، ويعرض هذه الإعدادات كمتغيرات بيئية أثناء التنفيذ.

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

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

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

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

languageWorkersnodearguments

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

Warning

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

logginglogLevelWorker

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

وحدات ECMAScript (المعاينة)

Note

نظرا لأن وحدات ECMAScript هي حاليا ميزة معاينة في Node.js 14 أو أعلى في دالات Azure.

وحدات ECMAScript (وحدات ES) هي نظام الوحدة القياسية الرسمي الجديد ل Node.js. حتى الآن، تستخدم نماذج التعليمات البرمجية في هذه المقالة بناء الجملة CommonJS. عند تشغيل دالات Azure في Node.js 14 أو أعلى، يمكنك اختيار كتابة دوالك باستخدام بناء جملة وحدات ES.

لاستخدام الوحدات ES في وظيفة، غير اسم الملف الخاص بها لاستخدام ملحق . مثال ملف index.mjs التالي هو دالة يتم تشغيلها بواسطة HTTP تستخدم بناء جملة الوحدات النمطية ES لاستيراد المكتبة وإرجاع قيمة.

  • JavaScript
  • TypeScript
import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(context, request) {
  context.res.body = uuidv4();
}

export default httpTrigger;
  • JavaScript
  • TypeScript
import { v4 as uuidv4 } from "uuid";

async function httpTrigger1(request, context) {
  return { body: uuidv4() };
}

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

تكوين نقطة إدخال الوظيفة

يمكن استخدام الخصائص و لتكوين موقع واسم الوظيفة المصدرة. الخاصية مطلوبة عند استخدام TypeScript ويجب أن تشير إلى JavaScript المحول برمجيا.

استخدام

بشكل افتراضي، يتم تنفيذ وظيفة JavaScript من ، ملف يشارك نفس الدليل الأصل الذي يشاركه الملف المطابق له .

يمكن استخدام للحصول على بنية مجلد مماثل للمثال التالي:

<project_root>/
 | - node_modules/
 | - myFirstFunction/
 | | - function.json
 | - lib/
 | | - sayHello.js
 | - host.json
 | - package.json

الخاص بـ يجب أن يتضمن خاصية للإشارة إلى الملف الذي يحتوي على الوظيفة المصدرة لتشغيله.

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

استخدام

في نموذج v3، يجب تصدير دالة باستخدام من أجل العثور عليها وتشغيلها. بشكل افتراضي، الوظيفة التي تنفذ عند تشغيلها هي التصدير الوحيد من ذلك الملف، أو التصدير المسمى ، أو التصدير المسمى . يعين المثال التالي إلى قيمة مخصصة، "logHello":

{
  "entryPoint": "logHello",
  "bindings": [
    ...
  ]
}
  • JavaScript
  • TypeScript
async function logHello(context) {
  context.log("Hello, world!");
}

module.exports = { logHello };

تصحيح الأخطاء المحلي

نوصي باستخدام VS Code لتصحيح الأخطاء المحلي، والذي يبدأ عملية Node.js في وضع التصحيح تلقائيا ويرفق بالعملية نيابة عنك. لمزيد من المعلومات، راجع تشغيل الدالة محليا.

إذا كنت تستخدم أداة مختلفة لتصحيح الأخطاء أو ترغب في بدء عملية Node.js في وضع التصحيح يدويا ، فقم بإضافة أسفل في local.settings.json. تخبر الوسيطة Node.js بالاستماع لعميل تصحيح الأخطاء، على المنفذ 9229 بشكل افتراضي. لمزيد من المعلومات، راجع دليل تصحيح الأخطاء Node.js.

Recommendations

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

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

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

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

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

استخدام عميل ثابت واحد

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

استخدام و

عند كتابة دالات Azure في Node.js، يجب أن تكتب كودا باستخدام الكلمات المفتاحية async و await. كتابة التعليمات البرمجية باستخدام و بدلاً من عمليات إعادة الاتصال أو و مع وعود تساعد على تجنب مشكلتين شائعتين:

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

في المثال التالي، يتم استدعاء الأسلوب غير المتزامن مع دالة رد اتصال الخطأ الأول كمعلمة ثانية. تتسبب هذه التعليمة البرمجية في كلتا المشكلتين المذكورتين سابقا. يمكن أن يؤدي الاستثناء الذي لم يتم اكتشافه بشكل صريح في النطاق الصحيح إلى تعطل العملية بأكملها (المشكلة رقم 1). العودة دون التأكد من انتهاء رد الاتصال يعني أن استجابة http تحتوي في بعض الأحيان على نص فارغ (المشكلة رقم 2).

  • JavaScript
  • TypeScript
// 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 };
    },
});

في المثال التالي، يتم استدعاء الأسلوب غير المتزامن مع دالة رد اتصال الخطأ الأول كمعلمة ثانية. تتسبب هذه التعليمة البرمجية في كلتا المشكلتين المذكورتين سابقا. يمكن أن يؤدي الاستثناء الذي لم يتم اكتشافه بشكل صريح في النطاق الصحيح إلى تعطل العملية بأكملها (المشكلة رقم 1). يمكن أن يشير استدعاء الأسلوب المهمل خارج نطاق رد الاتصال إلى انتهاء الدالة قبل قراءة الملف (المشكلة رقم 2). في هذا المثال، الاتصال بـ مبكرة جدًا يؤدي إلى إدخالات سجل مفقودة بدءًا من .

  • JavaScript
  • TypeScript
// 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();
};

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

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

  • JavaScript
  • TypeScript
// 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;
        }
    },
});

مع و، لا تحتاج أيضًا إلى استدعاء إعادة الاتصال .

  • JavaScript
  • TypeScript
// 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}`);
};

Troubleshoot

راجع دليل استكشاف الأخطاء وإصلاحها Node.js.

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

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