پلاگین های سفارشی را توسعه دهید

شما در حال مشاهده مستندات Apigee Edge هستید.
به مستندات Apigee X مراجعه کنید .
اطلاعات

میکروگیت‌وی اج نسخه ۳.۳.x

مخاطب

این مبحث برای توسعه‌دهندگانی در نظر گرفته شده است که مایل به گسترش ویژگی‌های Edge Microgateway با نوشتن افزونه‌های سفارشی هستند. اگر مایل به نوشتن افزونه جدیدی هستید، تجربه کار با جاوا اسکریپت و Node.js الزامی است.

افزونه سفارشی Edge Microgateway چیست؟

یک افزونه، یک ماژول Node.js است که قابلیتی را به Edge Microgateway اضافه می‌کند. ماژول‌های افزونه از یک الگوی ثابت پیروی می‌کنند و در مکانی که برای Edge Microgateway شناخته شده است، ذخیره می‌شوند و این امر امکان کشف و اجرای خودکار آنها را فراهم می‌کند. چندین افزونه از پیش تعریف شده هنگام نصب Edge Microgateway ارائه می‌شوند. این افزونه‌ها شامل افزونه‌هایی برای احراز هویت، جلوگیری از افزایش ناگهانی سرعت، سهمیه‌بندی و تجزیه و تحلیل هستند. این افزونه‌های موجود در بخش «استفاده از افزونه‌ها» توضیح داده شده‌اند.

شما می‌توانید با نوشتن افزونه‌های سفارشی ، ویژگی‌ها و قابلیت‌های جدیدی را به میکروگیت‌وی اضافه کنید. به طور پیش‌فرض، میکروگیت‌وی اج اساساً یک پروکسی امن عبوری است که درخواست‌ها و پاسخ‌ها را بدون تغییر به سرویس‌های هدف منتقل می‌کند. با افزونه‌های سفارشی، می‌توانید به صورت برنامه‌نویسی شده با درخواست‌ها و پاسخ‌هایی که از طریق میکروگیت‌وی جریان دارند، تعامل داشته باشید.

کد افزونه سفارشی را کجا قرار دهیم

پوشه‌ای برای افزونه‌های سفارشی به عنوان بخشی از نصب Edge Microgateway در اینجا گنجانده شده است:

[prefix]/lib/node_modules/edgemicro/node_modules/microgateway-plugins

که در آن [prefix] دایرکتوری پیشوند npm است، همانطور که در بخش «Edge Microgateway کجا نصب شده است» در بخش نصب Edge Microgateway توضیح داده شده است.

شما می‌توانید این دایرکتوری پیش‌فرض افزونه‌ها را تغییر دهید. به «محل یافتن افزونه‌ها» مراجعه کنید.

بررسی افزونه‌های از پیش تعریف شده

قبل از اینکه سعی کنید افزونه خودتان را توسعه دهید، خوب است بررسی کنید که هیچ یک از افزونه‌های از پیش تعریف شده نیازهای شما را برآورده نمی‌کنند. این افزونه‌ها در مسیر زیر قرار دارند:

[prefix]/lib/node_modules/edgemicro/node_modules/microgateway-plugins

که در آن [prefix] دایرکتوری پیشوند npm است. همچنین به بخش «Edge Microgateway کجا نصب شده است» در بخش «نصب Edge Microgateway » مراجعه کنید.

برای جزئیات بیشتر، به افزونه‌های از پیش تعریف‌شده‌ی ارائه شده با Edge Microgateway نیز مراجعه کنید.

نوشتن یک افزونه ساده

در این بخش، مراحل مورد نیاز برای ایجاد یک افزونه ساده را بررسی خواهیم کرد. این افزونه داده‌های پاسخ (هر چه که باشد) را با رشته "Hello, World!" بازنویسی می‌کند و آن را در ترمینال چاپ می‌کند.

  1. اگر Edge Microgateway در حال اجرا است، همین حالا آن را متوقف کنید:
    edgemicro stop
  2. با استفاده از cd به دایرکتوری افزونه سفارشی بروید:

    cd [prefix]/lib/node_modules/edgemicro/plugins

    که در آن [prefix] دایرکتوری پیشوند npm است، همانطور که در بخش «Edge Microgateway کجا نصب شده است» در بخش نصب Edge Microgateway توضیح داده شده است.

  3. یک پروژه افزونه جدید به نام response-override ایجاد کنید و cd به آن دسترسی پیدا کنید:
    mkdir response-override && cd response-override
  4. یک پروژه Node.js جدید ایجاد کنید:
    npm init
    برای پذیرش پیش‌فرض‌ها، چندین بار دکمه‌ی Return را بزنید.
  5. با استفاده از یک ویرایشگر متن، فایل جدیدی به نام index.js ایجاد کنید.
  6. کد زیر را در index.js کپی کنید و فایل را ذخیره کنید.
    'use strict';
    var debug = require('debug')
    
    module.exports.init = function(config, logger, stats) {
    
      return {
       
        ondata_response: function(req, res, data, next) {
          debug('***** plugin ondata_response');
          next(null, null);
        },
        
        onend_response: function(req, res, data, next) {
          debug('***** plugin onend_response');
          next(null, "Hello, World!\n\n");
        }
      };
    }
  7. حالا شما یک افزونه ایجاد کرده‌اید و باید آن را به پیکربندی Edge Microgateway اضافه کنید. فایل $HOME/.edgemicro/[org]-[env]-config.yaml را باز کنید، که در آن org و env نام‌های سازمان و محیط Edge شما هستند.
  8. افزونه response-override را به عنصر plugins:sequence مطابق شکل زیر اضافه کنید.
          ...
          
          plugins:
            dir: ../plugins
            sequence:
              - oauth
              - response-override
              
          ...
  9. Edge Microgateway را مجدداً راه اندازی کنید.
  10. فراخوانی یک API از طریق Edge Microgateway. (این فراخوانی API فرض می‌کند که شما پیکربندی مشابه آموزش با امنیت کلید API را، همانطور که در راه‌اندازی و پیکربندی Edge Microgateway توضیح داده شده است، تنظیم کرده‌اید:
    curl -H 'x-api-key: uAM4gBSb6YoMvTHfx5lXJizYIpr5Jd' http://localhost:8000/hello/echo
    Hello, World!

آناتومی یک افزونه

افزونه نمونه Edge Microgateway که در ادامه آمده است، الگویی را که باید هنگام توسعه افزونه‌های خود دنبال کنید، نشان می‌دهد. کد منبع افزونه نمونه مورد بحث در این بخش در plugins/header-uppercase/index.js.

  • افزونه‌ها ماژول‌های استاندارد NPM هستند که فایل‌های package.json و index.js در پوشه ریشه دارند.
  • یک افزونه باید یک تابع init() را اکسپورت کند.
  • تابع init() سه آرگومان می‌گیرد: config ، logger و stats . این آرگومان‌ها در بخش آرگومان‌های تابع Plugin init() توضیح داده شده‌اند.
  • تابع init() یک شیء با نام تابع‌های هندلر (function handlers) برمی‌گرداند که هنگام وقوع رویدادهای خاص در طول عمر یک درخواست، فراخوانی می‌شوند.

توابع مدیریت رویداد

یک افزونه باید برخی یا همه این توابع مدیریت رویداد را پیاده‌سازی کند. پیاده‌سازی این توابع به شما بستگی دارد. هر تابع داده شده اختیاری است و یک افزونه معمولی حداقل زیرمجموعه‌ای از این توابع را پیاده‌سازی می‌کند.

کنترل‌کننده‌های رویداد جریان درخواست

این توابع در رویدادهای درخواست در Edge Microgateway فراخوانی می‌شوند.

  • onrequest
  • ondata_request
  • onend_request
  • onclose_request
  • onerror_request

onrequest درخواست

در ابتدای درخواست کلاینت فراخوانی می‌شود. این تابع زمانی فعال می‌شود که اولین بایت درخواست توسط Edge Microgateway دریافت شود. این تابع به شما امکان دسترسی به هدرهای درخواست، URL، پارامترهای پرس‌وجو و متد HTTP را می‌دهد. اگر تابع next را با یک آرگومان truthy first (مانند نمونه‌ای از Error) فراخوانی کنید، پردازش درخواست متوقف می‌شود و درخواست هدف آغاز نمی‌شود.

مثال:

onrequest: function(req, res, next) {
      debug('plugin onrequest');
      req.headers['x-foo-request-start'] = Date.now();
      next();
    }

تابع ondata_request

زمانی فراخوانی می‌شود که یک تکه داده از کلاینت دریافت شود. داده‌های درخواست را به افزونه بعدی در دنباله افزونه‌ها ارسال می‌کند. مقدار برگردانده شده از آخرین افزونه در دنباله به هدف ارسال می‌شود. یک مورد استفاده معمول، که در زیر نشان داده شده است، تبدیل داده‌های درخواست قبل از ارسال آن به هدف است.

مثال:

ondata_request: function(req, res, data, next) {
      debug('plugin ondata_request ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    }

تابع onend_request

زمانی فراخوانی می‌شود که تمام داده‌های درخواست از کلاینت دریافت شده باشد.

مثال:

onend_request: function(req, res, data, next) {
      debug('plugin onend_request');
      next(null, data);
    }

تابع onclose_request

نشان می‌دهد که اتصال کلاینت بسته شده است. می‌توانید از این تابع در مواردی که اتصال کلاینت غیرقابل اعتماد است استفاده کنید. این تابع زمانی فراخوانی می‌شود که اتصال سوکت به کلاینت بسته شده باشد.

مثال:

onclose_request: function(req, res, next) {
      debug('plugin onclose_request');
      next();
    }

تابع onerror_request

در صورت بروز خطا در دریافت درخواست کلاینت، فراخوانی می‌شود.

مثال:

onerror_request: function(req, res, err, next) {
      debug('plugin onerror_request ' + err);
      next();
    }

گرداننده‌های رویداد جریان پاسخ

این توابع در رویدادهای پاسخ در Edge Microgateway فراخوانی می‌شوند.

  • onresponse
  • ondata_response
  • onend_response
  • onclose_response
  • onerror_response

تابع onresponse

در ابتدای پاسخ هدف فراخوانی می‌شود. این تابع زمانی اجرا می‌شود که اولین بایت پاسخ توسط Edge Microgateway دریافت شود. این تابع به شما امکان دسترسی به هدرهای پاسخ و کد وضعیت را می‌دهد.

مثال:

onresponse: function(req, res, next) {      
    debug('plugin onresponse');     
    res.setHeader('x-foo-response-time', Date.now() - req.headers['x-foo-request-start'])    
    next();    
}


تابع ondata_response

زمانی فراخوانی می‌شود که یک تکه داده از هدف دریافت شود.

مثال:

ondata_response: function(req, res, data, next) {
      debug('plugin ondata_response ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    }


تابع onend_response

زمانی فراخوانی می‌شود که تمام داده‌های پاسخ از هدف دریافت شده باشد.

مثال:

onend_response: function(req, res, data, next) {
      debug('plugin onend_response');
      next(null, data);
    }

تابع onclose_response

نشان می‌دهد که اتصال هدف بسته شده است. می‌توانید از این تابع در مواردی که اتصال هدف غیرقابل اعتماد است استفاده کنید. این تابع زمانی فراخوانی می‌شود که اتصال سوکت به هدف بسته شده باشد.

مثال:

onclose_response: function(req, res, next) {
      debug('plugin onclose_response');
      next();
    }


تابع onerror_response

در صورت بروز خطا در دریافت پاسخ هدف، فراخوانی می‌شود.

مثال:

onerror_response: function(req, res, err, next) {
      debug('plugin onerror_response ' + err);
      next();
    }

آنچه باید در مورد توابع مدیریت رویداد افزونه بدانید

توابع مدیریت رویداد افزونه در پاسخ به رویدادهای خاصی که هنگام پردازش یک درخواست API مشخص توسط Edge Microgateway رخ می‌دهند، فراخوانی می‌شوند.

  • هر یک از کنترل‌کننده‌های تابع init() ( مانند ondata_request ، ondata_response و غیره) باید پس از اتمام پردازش، تابع next() را فراخوانی کنند. اگر next() را فراخوانی نکنید، پردازش متوقف شده و درخواست متوقف می‌شود.
  • اولین آرگومان تابع next() ممکن است خطایی باشد که باعث خاتمه پردازش درخواست شود.
  • گرداننده‌های ondata_ و oneend_ باید تابع next() را با آرگومان دومی که شامل داده‌هایی است که قرار است به مقصد یا کلاینت ارسال شوند، فراخوانی کنند. اگر افزونه در حال بافر کردن باشد و در حال حاضر داده‌های کافی برای تبدیل نداشته باشد، این آرگومان می‌تواند تهی (null) باشد.
  • توجه داشته باشید که یک نمونه واحد از افزونه برای سرویس‌دهی به همه درخواست‌ها و پاسخ‌ها استفاده می‌شود. اگر افزونه‌ای بخواهد وضعیت هر درخواست را بین فراخوانی‌ها حفظ کند، می‌تواند آن وضعیت را در یک ویژگی اضافه شده به شیء درخواست ارائه شده ( req ) ذخیره کند، که طول عمر آن مدت زمان فراخوانی API است.
  • مراقب باشید که همه خطاها را بگیرید و تابع next() را برای خطا فراخوانی کنید. عدم فراخوانی next() منجر به هنگ کردن فراخوانی API خواهد شد.
  • مراقب باشید که نشت حافظه ایجاد نکنید زیرا این امر می‌تواند بر عملکرد کلی Edge Microgateway تأثیر بگذارد و در صورت کمبود حافظه، باعث خرابی آن شود.
  • مراقب باشید که از مدل Node.js پیروی کنید و وظایف محاسباتی سنگین را در ترد اصلی انجام ندهید، زیرا این امر می‌تواند بر عملکرد Edge Microgateway تأثیر منفی بگذارد.

درباره تابع init() افزونه

این بخش آرگومان‌های ارسالی به تابع init() را شرح می‌دهد: config ، logger و stats .

پیکربندی

داده‌های پیکربندی به‌دست‌آمده از ادغام فایل پیکربندی Edge Microgateway با داده‌های دانلود شده از Apigee Edge در شیء‌ای به نام config قرار می‌گیرند.

برای اضافه کردن یک پارامتر پیکربندی به نام param با مقدار foo به افزونه‌ای به نام response-override ، کد زیر را در فایل default.yaml قرار دهید:

response-override:
    param: foo

سپس، می‌توانید به این پارامتر در کد افزونه خود دسترسی پیدا کنید، مانند این:

// Called when response data is received
    ondata_response: function(req, res, data, next) {
      debug('***** plugin ondata_response');
      debug('***** plugin ondata_response: config.param: ' + config.param);
      next(null, data);
    },

در این حالت، foo را در خروجی اشکال‌زدایی افزونه مشاهده خواهید کرد:

Sun, 13 Dec 2015 21:25:08 GMT plugin:response-override ***** plugin ondata_response: config.param: foo

شما می‌توانید به پیکربندی ادغام‌شده‌ی microgateway و داده‌های دانلود شده‌ی Apigee Edge در شیء فرزند config.emgConfigs دسترسی داشته باشید. برای مثال، می‌توانید به این داده‌های پیکربندی در تابع init به صورت زیر دسترسی داشته باشید:

module.exports.init = function(config, logger, stats) {
   let emgconfigs = config.emgConfigs;

در زیر نمونه‌ای از داده‌هایی که emgConfigs شامل می‌شود، آمده است:

{
    edgemicro:
    {
        port: 8000,
        max_connections: 1000,
        config_change_poll_interval: 600,
        logging:
        {
            level: 'error',
            dir: '/var/tmp',
            stats_log_interval: 60,
            rotate_interval: 24,
            stack_trace: false
        },
        plugins: { sequence: [Array] },
        global: { org: 'Your Org', env: 'test' }
    },
    headers:
    {
        'x-forwarded-for': true,
        'x-forwarded-host': true,
        'x-request-id': true,
        'x-response-time': true,
        via: true
    },
    proxies:
    [    {
                max_connections: 1000,
                name: 'edgemicro_delayed',
                revision: '1',
                proxy_name: 'default',
                base_path: '/edgemicro_delayed',
                target_name: 'default',
                url: 'https://httpbin.org/delay/10',
                timeout: 0
            }
    ],
    product_to_proxy: { EdgeMicroTestProduct: [ 'edgemicro-auth','edgemicro_delayed',] },
    product_to_scopes: {prod4: [ 'Admin', 'Guest', 'Student' ] },
    product_to_api_resource: { EdgeMicroTestProduct: [ '/*' ] },
    _hash: 0,
    keys: { key: 'Your key', secret: 'Your key ' },
    uid: 'Internally generated uuid',
    targets: []
  }

چوب‌بر

ثبت‌کننده‌ی سیستم. ثبت‌کننده‌ی فعلی این توابع را صادر می‌کند، که در آن شیء می‌تواند یک رشته، درخواست HTTP، پاسخ HTTP یا یک نمونه خطا باشد.

  • info(object, message)
  • warn(object, message)
  • error(object, message)
  • trace(object, message)
  • debug(object, message)

آمار

شیء‌ای که تعداد درخواست‌ها، پاسخ‌ها، خطاها و سایر آمارهای تجمیع‌شده مربوط به درخواست‌ها و پاسخ‌های جاری از طریق یک نمونه‌ی میکروگیت‌وی را در خود نگه می‌دارد.

  • treqErrors - تعداد درخواست‌های هدف با خطا.
  • treqErrors - تعداد پاسخ‌های هدف با خطا.
  • statusCodes - یک شیء حاوی کد پاسخ موارد زیر را شمارش می‌کند:
{
  1: number of target responses with 1xx response codes
  2: number of target responses with 2xx response codes
  3: number of target responses with 3xx response codes
  4: number of target responses with 4xx response codes
  5: number of target responses with 5xx response codes
  }
  
  • درخواست‌ها - تعداد کل درخواست‌ها.
  • پاسخ‌ها - تعداد کل پاسخ‌ها.
  • اتصالات - تعداد اتصالات هدف فعال.

درباره تابع ()next

تمام متدهای افزونه باید تابع next() را برای ادامه پردازش متد بعدی در سری فراخوانی کنند (در غیر این صورت فرآیند افزونه متوقف خواهد شد). در چرخه حیات درخواست، اولین متدی که فراخوانی می‌شود onrequest() است. متد بعدی که فراخوانی می‌شود، متد ondata_request() است؛ با این حال، ondata_request فقط در صورتی فراخوانی می‌شود که درخواست شامل داده باشد، مانند موردی مانند درخواست POST. متد بعدی که فراخوانی می‌شود، onend_request() خواهد بود که پس از تکمیل پردازش درخواست فراخوانی می‌شود. توابع onerror_* فقط در صورت بروز خطا فراخوانی می‌شوند و به شما امکان می‌دهند در صورت تمایل، خطاها را با کد سفارشی مدیریت کنید.

فرض کنید داده‌ها در درخواست ارسال می‌شوند و ondata_request() فراخوانی می‌شود. توجه داشته باشید که تابع، next() را با دو پارامتر فراخوانی می‌کند:

next(null, data);

طبق قرارداد، اولین پارامتر برای انتقال اطلاعات خطا استفاده می‌شود که می‌توانید آن را در تابع بعدی در زنجیره مدیریت کنید. با تنظیم آن به null ، یک آرگومان falsy، می‌گوییم که هیچ خطایی وجود ندارد و پردازش درخواست باید به طور عادی ادامه یابد. اگر این آرگومان truthy باشد (مانند یک شیء Error)، پردازش درخواست متوقف می‌شود و درخواست به مقصد ارسال می‌شود.

پارامتر دوم، داده‌های درخواست را به تابع بعدی در زنجیره ارسال می‌کند. اگر هیچ پردازش اضافی انجام ندهید، داده‌های درخواست بدون تغییر به هدف API ارسال می‌شوند. با این حال، شما می‌توانید داده‌های درخواست را در این متد تغییر دهید و درخواست اصلاح‌شده را به هدف ارسال کنید. برای مثال، اگر داده‌های درخواست XML باشد و هدف انتظار JSON داشته باشد، می‌توانید کدی را به متد ondata_request() اضافه کنید که (الف) نوع محتوای هدر درخواست را به application/json تغییر دهد و داده‌های درخواست را با استفاده از هر روشی که می‌خواهید به JSON تبدیل کند (برای مثال، می‌توانید از مبدل xml2json Node.js که از NPM دریافت می‌کنید استفاده کنید).

بیایید ببینیم که چگونه ممکن است به نظر برسد:

ondata_request: function(req, res, data, next) {
  debug('****** plugin ondata_request');
  var translated_data = parser.toJson(data);
  next(null, translated_data);
},

در این حالت، داده‌های درخواست (که فرض می‌شود XML هستند) به JSON تبدیل می‌شوند و داده‌های تبدیل‌شده از طریق next() به تابع next در زنجیره درخواست، قبل از ارسال به مقصد backend، ارسال می‌شوند.

توجه داشته باشید که می‌توانید یک دستور اشکال‌زدایی دیگر برای چاپ داده‌های تبدیل‌شده جهت اشکال‌زدایی اضافه کنید. برای مثال:

ondata_request: function(req, res, data, next) {
  debug('****** plugin ondata_request');
  var translated_data = parser.toJson(data);
  debug('****** plugin ondata_response: translated_json: ' + translated_json);
  next(null, translated_data);
},

درباره ترتیب اجرای کنترل‌کننده افزونه

اگر افزونه‌هایی برای Edge Microgateway می‌نویسید، باید ترتیب اجرای کنترل‌کننده‌های رویداد افزونه را درک کنید.

نکته‌ی مهمی که باید به خاطر داشته باشید این است که وقتی یک توالی افزونه را در فایل پیکربندی Edge Microgateway مشخص می‌کنید، کنترل‌کننده‌های درخواست به ترتیب صعودی اجرا می‌شوند، در حالی که کنترل‌کننده‌های پاسخ به ترتیب نزولی اجرا می‌شوند.

مثال زیر برای کمک به شما در درک این توالی اجرا طراحی شده است.

۱. سه افزونه ساده ایجاد کنید

افزونه‌ی زیر را در نظر بگیرید. تنها کاری که انجام می‌دهد چاپ خروجی کنسول هنگام فراخوانی کنترل‌کننده‌های رویداد آن است:

افزونه‌ها/افزونه-۱/index.js

module.exports.init = function(config, logger, stats) {

  return {

    onrequest: function(req, res, next) {
      console.log('plugin-1: onrequest');
      next();
    },

    onend_request: function(req, res, data, next) {
      console.log('plugin-1: onend_request');
      next(null, data);
    },

    ondata_response: function(req, res, data, next) {
      console.log('plugin-1: ondata_response ' + data.length);
      next(null, data);
    },

    onend_response: function(req, res, data, next) {
      console.log('plugin-1: onend_response');
      next(null, data);
    }
  };
}

حالا، ایجاد دو افزونه‌ی دیگر، plugin-2 و plugin-3 ، را با همان کد در نظر بگیرید (به جز اینکه، عبارات console.log() را به ترتیب به plugin-2 و plugin-3 تغییر دهید).

۲. کد افزونه را بررسی کنید

توابع افزونه‌ی اکسپورت‌شده در <microgateway-root-dir>/plugins/plugin-1/index.js ، گرداننده‌های رویدادی هستند که در زمان‌های مشخصی در طول پردازش درخواست و پاسخ اجرا می‌شوند. برای مثال، onrequest اولین بایت از هدرهای درخواست را که دریافت می‌شود اجرا می‌کند. در حالی که، onend_response پس از دریافت آخرین بایت از داده‌های پاسخ اجرا می‌شود.

نگاهی به هندلر ondata_response بیندازید -- هر زمان که یک تکه از داده‌های پاسخ دریافت شود، فراخوانی می‌شود. نکته‌ی مهمی که باید بدانید این است که داده‌های پاسخ لزوماً همه به طور همزمان دریافت نمی‌شوند. بلکه، داده‌ها ممکن است در تکه‌هایی با طول دلخواه دریافت شوند.

۳. افزونه‌ها را به توالی افزونه‌ها اضافه کنید

در ادامه این مثال، افزونه‌ها را به ترتیب افزونه‌ها در فایل پیکربندی Edge Microgateway ( ~./edgemicro/config.yaml ) به صورت زیر اضافه خواهیم کرد. این ترتیب مهم است. این ترتیب، ترتیب اجرای کنترل‌کننده‌های افزونه را تعریف می‌کند.

  plugins:
    dir: ../plugins
    sequence:
      - plugin-1
      - plugin-2
      - plugin-3
  

۴. خروجی اشکال‌زدایی را بررسی کنید

حالا، بیایید نگاهی به خروجی که هنگام فراخوانی این افزونه‌ها تولید می‌شود، بیندازیم. چند نکته مهم وجود دارد که باید به آنها توجه کنید:

  • توالی افزونه در فایل پیکربندی Edge Microgateway ( ~./edgemicro/config.yaml ) ترتیب فراخوانی کنترل‌کننده‌های رویداد را مشخص می‌کند.
  • کنترل‌کننده‌های درخواست به ترتیب صعودی (به ترتیبی که در دنباله افزونه ظاهر می‌شوند -- ۱، ۲، ۳) فراخوانی می‌شوند.
  • کنترل‌کننده‌های پاسخ به ترتیب نزولی فراخوانی می‌شوند -- ۳، ۲، ۱.
  • کنترل‌کننده‌ی ondata_response به ازای هر تکه داده‌ای که می‌رسد، یک بار فراخوانی می‌شود. در این مثال (خروجی نشان داده شده در زیر)، دو تکه داده دریافت می‌شود.

در اینجا نمونه‌ای از خروجی اشکال‌زدایی که هنگام استفاده از این سه افزونه و ارسال درخواست از طریق Edge Microgateway تولید می‌شود، آمده است. فقط به ترتیب فراخوانی هندلرها توجه کنید:

  plugin-1: onrequest
  plugin-2: onrequest
  plugin-3: onrequest

  plugin-1: onend_request
  plugin-2: onend_request
  plugin-3: onend_request

  plugin-3: ondata_response 931
  plugin-2: ondata_response 931
  plugin-1: ondata_response 931

  plugin-3: ondata_response 1808
  plugin-3: onend_response

  plugin-2: ondata_response 1808
  plugin-2: onend_response

  plugin-1: ondata_response 1808
  plugin-1: onend_response

خلاصه

درک ترتیب فراخوانی کنترل‌کننده‌های افزونه هنگام پیاده‌سازی قابلیت‌های سفارشی افزونه، مانند جمع‌آوری و تبدیل داده‌های درخواست یا پاسخ، بسیار مهم است.

فقط به یاد داشته باشید که کنترل‌کننده‌های درخواست به ترتیبی که افزونه‌ها در فایل پیکربندی Edge Microgateway مشخص شده‌اند، اجرا می‌شوند و کنترل‌کننده‌های پاسخ به ترتیب مخالف اجرا می‌شوند.

درباره استفاده از متغیرهای سراسری در افزونه‌ها

هر درخواست به Edge Microgateway به همان نمونه از یک افزونه ارسال می‌شود؛ بنابراین، وضعیت درخواست دوم از یک کلاینت دیگر، وضعیت درخواست اول را بازنویسی می‌کند. تنها مکان امن برای ذخیره وضعیت افزونه، ذخیره وضعیت در یک ویژگی روی شیء درخواست یا پاسخ است (که طول عمر آن محدود به طول عمر درخواست است).

بازنویسی URL های هدف در افزونه ها

اضافه شده در: نسخه ۲.۳.۳

شما می‌توانید با تغییر این متغیرها در کد افزونه خود، آدرس اینترنتی هدف پیش‌فرض را در یک افزونه به صورت پویا لغو کنید: req.targetHostname و req.targetPath .

اضافه شده در: نسخه ۲.۴.x

همچنین می‌توانید پورت نقطه پایانی هدف را نادیده بگیرید و بین HTTP و HTTPS یکی را انتخاب کنید. این متغیرها را در کد افزونه خود تغییر دهید: req.targetPort و req.targetSecure . برای انتخاب HTTPS، req.targetSecure را روی true تنظیم کنید؛ برای HTTP، آن را روی false تنظیم کنید. اگر req.targetSecure را روی true تنظیم کرده‌اید، برای اطلاعات بیشتر به این تاپیک بحث مراجعه کنید.

حذف شده در: نسخه ۳.۳.۳

افزونه نمونه به نام eurekaclient در نسخه ۳.۳.۳ از Edge Microgateway حذف شد. به یادداشت‌های انتشار مراجعه کنید.

حذف این ویژگی بر عملکرد اصلی Edge microgateway یا بازنویسی URL های هدف تأثیری ندارد. می‌توانید جستجوی پویای نقطه پایانی را پیکربندی کنید و متغیرهای هدف مانند req.targetHostname ، req.targetPath ، req.targetPort و req.targetSecure را در سطح افزونه نادیده بگیرید. به بخش بازنویسی URL های هدف در افزونه‌ها مراجعه کنید.


افزونه‌های نمونه

این افزونه‌ها همراه با نصب Edge Microgateway شما ارائه می‌شوند. می‌توانید آن‌ها را در نصب Edge Microgateway در اینجا پیدا کنید:

[prefix]/lib/node_modules/edgemicro/plugins

که در آن [prefix] دایرکتوری پیشوند npm است، همانطور که در بخش «Edge Microgateway کجا نصب شده است» در بخش نصب Edge Microgateway توضیح داده شده است.

درخواست انباشت

این افزونه، تکه‌های داده را از کلاینت در یک ویژگی آرایه متصل به شیء درخواست جمع‌آوری می‌کند. هنگامی که تمام داده‌های درخواست دریافت شد، آرایه در یک بافر (Buffer) ادغام می‌شود که سپس به افزونه بعدی در دنباله ارسال می‌شود. این افزونه باید اولین افزونه در دنباله باشد تا افزونه‌های بعدی داده‌های درخواست جمع‌آوری‌شده را دریافت کنند.

module.exports.init = function(config, logger, stats) {

  function accumulate(req, data) {

    if (!req._chunks) req._chunks = [];
    req._chunks.push(data);

  }

  return {

    ondata_request: function(req, res, data, next) {

      if (data && data.length > 0) accumulate(req, data);

      next(null, null);

    },


    onend_request: function(req, res, data, next) {

      if (data && data.length > 0) accumulate(req, data);

      var content = null;

      if (req._chunks && req._chunks.length) {

        content = Buffer.concat(req._chunks);

      }

      delete req._chunks;

      next(null, content);

    }

  };

}

تجمع-پاسخ

این افزونه، تکه‌های داده را از هدف در یک ویژگی آرایه متصل به شیء پاسخ جمع‌آوری می‌کند. هنگامی که تمام داده‌های پاسخ دریافت شد، آرایه در یک بافر (Buffer) ادغام می‌شود که سپس به افزونه بعدی در دنباله ارسال می‌شود. از آنجا که این افزونه روی پاسخ‌هایی کار می‌کند که به ترتیب معکوس پردازش می‌شوند، باید آن را به عنوان آخرین افزونه در دنباله قرار دهید.

module.exports.init = function(config, logger, stats) {

  function accumulate(res, data) {
    if (!res._chunks) res._chunks = [];
    res._chunks.push(data);
  }

  return {

    ondata_response: function(req, res, data, next) {
      if (data && data.length > 0) accumulate(res, data);
      next(null, null);
    },

    onend_response: function(req, res, data, next) {
      if (data && data.length > 0) accumulate(res, data);
      var content = Buffer.concat(res._chunks);
      delete res._chunks;
      next(null, content);
    }

  };

}

افزونه‌ی سربرگ با حروف بزرگ

توزیع‌های Edge Microgateway شامل یک افزونه نمونه به نام <microgateway-root-dir>/plugins/header-uppercase هستند. این نمونه شامل توضیحاتی است که هر یک از کنترل‌کننده‌های تابع را توصیف می‌کند. این نمونه، تبدیل داده‌های ساده‌ای را در پاسخ هدف انجام می‌دهد و هدرهای سفارشی را به درخواست کلاینت و پاسخ هدف اضافه می‌کند.

کد منبع برای <microgateway-root-dir>/plugins/header-uppercase/index.js به صورت زیر است:

'use strict';

var debug = require('debug')('plugin:header-uppercase');

// required
module.exports.init = function(config, logger, stats) {

  var counter = 0;

  return {

    // indicates start of client request
    // request headers, url, query params, method should be available at this time
    // request processing stops (and a target request is not initiated) if
    // next is called with a truthy first argument (an instance of Error, for example)
    onrequest: function(req, res, next) {
      debug('plugin onrequest');
      req.headers['x-foo-request-id'] = counter++;
      req.headers['x-foo-request-start'] = Date.now();
      next();
    },

    // indicates start of target response
    // response headers and status code should be available at this time
    onresponse: function(req, res, next) {
      debug('plugin onresponse');
      res.setHeader('x-foo-response-id', req.headers['x-foo-request-id']);
      res.setHeader('x-foo-response-time', Date.now() - req.headers['x-foo-request-start']);
      next();
    },

    // chunk of request body data received from client
    // should return (potentially) transformed data for next plugin in chain
    // the returned value from the last plugin in the chain is written to the target
    ondata_request: function(req, res, data, next) {
      debug('plugin ondata_request ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    },

    // chunk of response body data received from target
    // should return (potentially) transformed data for next plugin in chain
    // the returned value from the last plugin in the chain is written to the client
    ondata_response: function(req, res, data, next) {
      debug('plugin ondata_response ' + data.length);
      var transformed = data.toString().toUpperCase();
      next(null, transformed);
    },

    // indicates end of client request
    onend_request: function(req, res, data, next) {
      debug('plugin onend_request');
      next(null, data);
    },

    // indicates end of target response
    onend_response: function(req, res, data, next) {
      debug('plugin onend_response');
      next(null, data);
    },

    // error receiving client request
    onerror_request: function(req, res, err, next) {
      debug('plugin onerror_request ' + err);
      next();
    },

    // error receiving target response
    onerror_response: function(req, res, err, next) {
      debug('plugin onerror_response ' + err);
      next();
    },

    // indicates client connection closed
    onclose_request: function(req, res, next) {
      debug('plugin onclose_request');
      next();
    },

    // indicates target connection closed
    onclose_response: function(req, res, next) {
      debug('plugin onclose_response');
      next();
    }

  };

}

تبدیل-حروف بزرگ

این یک افزونه‌ی تبدیل عمومی است که می‌توانید آن را برای انجام هر نوع تبدیلی که می‌خواهید تغییر دهید. این مثال به سادگی داده‌های پاسخ و درخواست را به حروف بزرگ تبدیل می‌کند.

 */
module.exports.init = function(config, logger, stats) {

  // perform content transformation here
  // the result of the transformation must be another Buffer
  function transform(data) {
    return new Buffer(data.toString().toUpperCase());
  }

  return {

    ondata_response: function(req, res, data, next) {
      // transform each chunk as it is received
      next(null, data ? transform(data) : null);
    },

    onend_response: function(req, res, data, next) {
      // transform accumulated data, if any
      next(null, data ? transform(data) : null);
    },

    ondata_request: function(req, res, data, next) {
      // transform each chunk as it is received
      next(null, data ? transform(data) : null);
    },

    onend_request: function(req, res, data, next) {
      // transform accumulated data, if any
      next(null, data ? transform(data) : null);
    }

  };

}