Вы просматриваете документацию по Apigee Edge.
Перейдите к документации по Apigee X. Информация
Edge Microgateway версии 3.1.5 и более поздних
Аудитория
Эта статья предназначена для разработчиков, которые хотят расширить возможности 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); } }; }