Вы просматриваете документацию по Apigee Edge.
Перейдите к документации по Apigee X. Информация
Edge Microgateway версии 3.2.x
Аудитория
Эта статья предназначена для разработчиков, которые хотят расширить возможности Edge Microgateway, написав собственные плагины. Если вы хотите написать новый плагин, вам потребуется опыт работы с JavaScript и Node.js.
Что такое специальный плагин Edge Microgateway?
Плагин – это модуль Node.js, который добавляет функции в Edge Microgateway. Модули плагинов следуют единому шаблону и хранятся в месте, известном 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!" и выводит ее в терминал.
- Если Edge Microgateway запущен, остановите его:
edgemicro stop
-
cdв каталог специальных плагинов:cd [prefix]/lib/node_modules/edgemicro/pluginsгде
[prefix]– это каталог с префиксомnpm, как описано в разделе "Где устанавливается Edge Microgateway" статьи Установка Edge Microgateway. - Создайте новый проект плагина с названием response-override и добавьте в него
cdследующий код:
mkdir response-override && cd response-override
- Создайте новый проект Node.js:
Нажимайте клавишу Ввод несколько раз, чтобы принять значения по умолчанию.npm init
- С помощью текстового редактора создайте новый файл с названием
index.js. - Скопируйте следующий код в файл
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"); } }; }
- Теперь, когда вы создали плагин, вам нужно добавить его в конфигурацию Edge Microgateway.
Откройте файл
$HOME/.edgemicro/[org]-[env]-config.yaml, гдеorgиenv– названия организации и среды Edge. - Добавьте плагин
response-overrideв элементplugins:sequence, как показано ниже.
... plugins: dir: ../plugins sequence: - oauth - response-override ... - Перезапустите Edge Microgateway.
- Вызов 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() возвращает объект с именованными обработчиками функций, которые вызываются при возникновении определенных событий в течение срока действия запроса.
Функции обработчика событий
Плагин должен реализовать некоторые или все из этих функций обработчика событий. Реализация этих функций зависит от вас. Любая из этих функций является необязательной, и типичный плагин реализует хотя бы часть из них.
Обработчики событий запроса потока
Эти функции вызываются при событиях запроса в Edge Microgateway.
onrequestondata_requestonend_requestonclose_requestonerror_request
onrequest function
Вызывается в начале клиентского запроса. Эта функция запускается, когда Edge Microgateway получает первый байт запроса. Эта функция предоставляет доступ к заголовкам запроса, URL, параметрам запроса и методу HTTP. Если вы вызовете next с истинным первым аргументом (например, экземпляром Error), обработка запроса прекратится и целевой запрос не будет инициирован.
Пример:
onrequest: function(req, res, next) { debug('plugin onrequest'); req.headers['x-foo-request-start'] = Date.now(); next(); }
ondata_request function
Вызывается, когда от клиента получен фрагмент данных. Передает данные запроса следующему плагину в последовательности. Значение, возвращенное последним плагином в последовательности, отправляется в целевой объект. Ниже приведен типичный пример использования, в котором данные запроса преобразуются перед отправкой в целевой объект.
Пример:
ondata_request: function(req, res, data, next) { debug('plugin ondata_request ' + data.length); var transformed = data.toString().toUpperCase(); next(null, transformed); }
onend_request function
Вызывается, когда от клиента получены все данные запроса.
Пример:
onend_request: function(req, res, data, next) { debug('plugin onend_request'); next(null, data); }
onclose_request function
Указывает, что подключение клиента закрыто. Эту функцию можно использовать, если подключение клиента ненадежно. Она вызывается, когда закрывается подключение сокета к клиенту.
Пример:
onclose_request: function(req, res, next) { debug('plugin onclose_request'); next(); }
onerror_request function
Вызывается, если при получении клиентского запроса произошла ошибка.
Пример:
onerror_request: function(req, res, err, next) { debug('plugin onerror_request ' + err); next(); }
Обработчики событий потока ответов
Эти функции вызываются при событиях ответа в Edge Microgateway.
onresponseondata_responseonend_responseonclose_responseonerror_response
onresponse function
Вызывается в начале целевого ответа. Эта функция запускается, когда 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 function
Вызывается, когда от целевого объекта получен фрагмент данных.
Пример:
ondata_response: function(req, res, data, next) { debug('plugin ondata_response ' + data.length); var transformed = data.toString().toUpperCase(); next(null, transformed); }
onend_response function
Вызывается, когда от целевого объекта получены все данные ответа.
Пример:
onend_response: function(req, res, data, next) { debug('plugin onend_response'); next(null, data); }
onclose_response function
Указывает, что целевое подключение закрыто. Эту функцию можно использовать, если целевое подключение ненадежно. Он вызывается, когда закрывается подключение сокета к целевому объекту.
Пример:
onclose_response: function(req, res, next) { debug('plugin onclose_response'); next(); }
onerror_response function
Вызывается, если при получении целевого ответа произошла ошибка.
Пример:
onerror_response: function(req, res, err, next) { debug('plugin onerror_response ' + err); next(); }
Что нужно знать о функциях обработчика событий плагина
Функции обработчика событий плагина вызываются в ответ на определенные события, которые происходят, когда Edge Microgateway обрабатывает определенный запрос к API.
- Каждый обработчик функции init() (ondata_request, ondata_response и т. д.) должен вызывать функцию обратного вызова next() после завершения обработки. Если вы не вызовете функцию next(), обработка остановится и запрос зависнет.
- Первый аргумент функции next() может быть ошибкой, которая приведет к прекращению обработки запроса.
- Обработчики ondata_ и onend_ должны вызывать функцию next() со вторым аргументом, содержащим данные, которые будут переданы целевому объекту или клиенту. Этот аргумент может быть нулевым, если плагин буферизует данные и в данный момент их недостаточно для преобразования.
- Обратите внимание, что для обработки всех запросов и ответов используется один экземпляр плагина. Если плагину необходимо сохранить состояние запроса между вызовами, он может сохранить это состояние в свойстве, добавленном в предоставленный объект request (req), время жизни которого равно длительности вызова API.
- Обязательно обработайте все ошибки и вызовите функцию next() с ошибкой. Если не вызвать функцию next(), вызов API зависнет.
- Будьте осторожны, чтобы не допустить утечки памяти, поскольку это может повлиять на общую производительность микрошлюза Edge и привести к его сбою при нехватке памяти.
- Следуйте модели Node.js и не выполняйте ресурсоемкие задачи в основном потоке, так как это может негативно повлиять на производительность Edge Microgateway.
Функция init() плагина
В этом разделе описаны аргументы, передаваемые функции init(): config, logger и stats.
config
Данные конфигурации, полученные путем объединения файла конфигурации 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
Объединенную конфигурацию микрошлюза и скачанные данные 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: []
}
logger
Системный регистратор. Используемый в данный момент регистратор экспортирует эти функции, где объект может быть строкой, 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
}
- requests – общее количество запросов.
- responses – общее количество ответов.
- connections – количество активных целевых подключений.
Функция next()
Все методы плагина должны вызывать next(), чтобы продолжить обработку следующего метода в серии (иначе процесс плагина зависнет). В жизненном цикле запроса первым вызывается метод onrequest(). Следующим вызывается метод ondata_request(), однако ondata_request вызывается только в том случае, если запрос содержит данные, например в случае запроса POST. Следующим будет вызван метод onend_request(), который вызывается по завершении обработки запроса. Функции onerror_* вызываются только в случае ошибки и позволяют обрабатывать ошибки с помощью собственного кода.
Предположим, что данные отправляются в запросе и вызывается функция ondata_request(). Обратите внимание, что функция вызывает next() с двумя параметрами:
next(null, data);
По соглашению первый параметр используется для передачи информации об ошибке, которую затем можно обработать в следующей функции цепочки. Если задать значение null, то есть ложный аргумент, мы сообщаем, что ошибок нет и обработка запроса должна выполняться в обычном режиме. Если этот аргумент истинный (например, объект 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() следующей функции в цепочке запроса, после чего отправляются в целевой сервер.
Вы также можете добавить ещё одну инструкцию отладки, чтобы распечатать преобразованные данные. Пример:
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 обработчики запросов выполняются в возрастающем порядке, а обработчики ответов – в убывающем.
Приведенный ниже пример поможет вам понять последовательность выполнения.
1. Создайте три простых плагина
Рассмотрим следующий плагин. Он только выводит в консоль данные, когда вызываются его обработчики событий:
plugins/plugin-1/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 соответственно.
2. Проверьте код плагина
Экспортированные функции плагина в <microgateway-root-dir>/plugins/plugin-1/index.js – это обработчики событий, которые выполняются в определенное время при обработке запросов и ответов. Например, onrequest выполняется, когда получен первый байт заголовков запроса. В то же время onend_response выполняется после получения последнего байта данных ответа.
Обратите внимание на обработчик ondata_response. Он вызывается при получении каждого фрагмента данных ответа. Важно помнить, что данные ответов не всегда приходят одновременно. Данные могут быть получены в виде фрагментов произвольной длины.
3. Добавьте плагины в последовательность плагинов
Продолжая этот пример, мы добавим плагины в последовательность плагинов в файле конфигурации Edge Microgateway (~./edgemicro/config.yaml) следующим образом: Порядок действий важен. Он определяет порядок выполнения обработчиков плагинов.
plugins:
dir: ../plugins
sequence:
- plugin-1
- plugin-2
- plugin-3
4. Как проверить результат отладки
Теперь посмотрим, что произойдет, когда будут вызваны эти плагины. Вот несколько важных моментов:
- Последовательность плагинов в файле конфигурации Edge Microgateway (
~./edgemicro/config.yaml) определяет порядок вызова обработчиков событий. - Обработчики запросов вызываются в возрастающем порядке (в том порядке, в котором они появляются в последовательности плагинов – 1, 2, 3).
- Обработчики ответов вызываются в обратном порядке: 3, 2, 1.
- Обработчик
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 в плагинах
Добавлено в версии 2.3.3
Вы можете переопределить целевой URL по умолчанию в плагине, изменив в его коде переменные req.targetHostname и req.targetPath.
Добавлено в версии 2.4.x
Вы также можете переопределить целевой порт конечной точки и выбрать протокол HTTP или HTTPS. Измените следующие переменные в коде плагина: req.targetPort и req.targetSecure. Чтобы выбрать HTTPS, задайте для параметра req.targetSecure значение true, а для HTTP – false. Если вы задали для параметра req.targetSecure значение true, ознакомьтесь с этой темой на форуме.
Примеры плагинов
Эти плагины поставляются вместе с Edge Microgateway. Их можно найти в установке Edge Microgateway по следующему пути:
[prefix]/lib/node_modules/edgemicro/plugins
где [prefix] – это каталог с префиксом npm, как описано в разделе "Где устанавливается Edge Microgateway" статьи Установка Edge Microgateway.
accumulate-request
Этот плагин накапливает фрагменты данных от клиента в свойстве массива, прикрепленном к объекту запроса. Когда все данные запроса получены, массив объединяется в буфер, который затем передается следующему плагину в последовательности. Этот плагин должен быть первым в последовательности, чтобы последующие плагины получали накопленные данные запроса.
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); } }; }
accumulate-response
Этот плагин накапливает фрагменты данных из целевого объекта в свойстве массива, прикрепленном к объекту ответа. Когда все данные ответа получены, массив объединяется в буфер, который затем передается следующему плагину в последовательности. Поскольку этот плагин работает с ответами, которые обрабатываются в обратном порядке, его следует разместить последним в последовательности.
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); } }; }
Плагин header-uppercase
В дистрибутивы 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(); } }; }
transform-uppercase
Это общий плагин преобразования, который можно изменить, чтобы выполнить любое преобразование. В этом примере данные запроса и ответа просто преобразуются в верхний регистр.
*/ 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); } }; }