Как написать промежуточное ПО для Express.js

Введение Вы когда-нибудь задумывались, что происходит во всем промежуточном программном обеспечении Express.js, которое вы добавляете в свое веб-приложение? На самом деле довольно впечатляет, какие функции вы можете добавить в свои приложения с помощью одной или нескольких строк кода: // требуется ... var app = express (); app.use ("/ static", express.static (__ dirname + "/ public")); app.use (cookieParser ('секрет')); app.use (compress ()); Последние три строки выше обрабатывают для нас немалую часть функциональности веб-приложения. Первый app.use ()

Вступление

Вы когда-нибудь задумывались, что происходит во всем промежуточном программном обеспечении Express.js, которое вы добавляете в свое веб-приложение? На самом деле довольно впечатляет, какие функции вы можете добавить в свои приложения с помощью одной или нескольких строк кода:

 // requires... 
 
 var app = express(); 
 
 app.use("/static", express.static(__dirname + "/public")); 
 app.use(cookieParser('sekret')); 
 app.use(compress()); 

Последние три строки выше обрабатывают для нас немалую часть функциональности веб-приложения. Первый app.use() сообщает Express, где находятся наши статические файлы и как их раскрыть, cookieParser('sekret') обрабатывает весь синтаксический анализ файлов cookie (с шифрованием), а последний автоматически gzip сжимает все наши HTTP-файлы. данные тела. Неплохо всего для трех строк кода.

Это промежуточное программное обеспечение довольно типично для вашего обычного веб-приложения, но вы можете найти такие, которые делают больше, чем просто стандартное сжатие данных или синтаксический анализ файлов cookie. Возьмем, к примеру:

  • шлем : помогает защитить ваше приложение, устанавливая различные заголовки HTTP.
  • express-simple-cdn
    легко использовать CDN для ваших статических ресурсов
  • join-io : объединяйте файлы на лету, чтобы уменьшить количество HTTP-запросов
  • Паспорт : добавляет аутентификацию пользователя к выбранным маршрутам

И вот гораздо больший список промежуточного программного обеспечения, которое вы, возможно, захотите использовать.

Теперь, когда вы видели несколько примеров, вот все, что вы можете с ним сделать:

  • Выполнять любой код, в том числе асинхронный.
  • Вносить изменения или дополнения в объекты запроса и ответа
  • Завершить цикл запрос-ответ
  • Вызвать следующее промежуточное ПО в стеке

Учитывая безграничные возможности, я уверен, что у вас есть несколько собственных идей, которые вы бы хотели воплотить в жизнь, поэтому в оставшейся части этой статьи я буду показывать вам, как написать собственное промежуточное программное обеспечение. Вы можете написать несколько различных типов промежуточного программного обеспечения (приложение, маршрутизатор, обработка ошибок и т. Д.), Но в этой статье мы сосредоточимся только на уровне приложения.

Основы

Промежуточное ПО можно рассматривать как экспресс-маршрут. Они принимают те же параметры и все остальное, но, в отличие от обычных маршрутов, вам не требуется указывать URL-путь для промежуточного программного обеспечения. Двумя самыми большими различиями являются способ обработки пути и время его вызова.

Предоставленный путь рассматривается как префикс, поэтому, если у вас было что-то вроде app.use('/api', ...) , ваше промежуточное ПО будет работать, если вызывается /api и если /api/users . Это отличается от маршрутов, где путь должен быть точным.

Путь URL-адреса можно опустить в app.use() если вы хотите, чтобы ваш код выполнялся для всех запросов, в противном случае вы можете указать путь, и ваш код будет запускаться только тогда, когда этот маршрут (и все его подмаршруты) просил. Например, это может быть полезно для добавления аутентификации только для нескольких заданных маршрутов.

Простое промежуточное ПО может выглядеть так:

 var app = express(); 
 
 app.use(function(req, res, next) { 
 console.log('Called URL:', req.url); 
 next(); 
 }); 

Тогда как обработчик маршрута выглядит так:

 var app = express(); 
 
 app.get('/', function(req, res, next) { 
 res.send('Hey there...'); 
 }); 

Видеть? По сути, это одно и то же, поэтому написание этих функций должно быть вам знакомо.

Используются следующие параметры:

  • req : объект, содержащий всю необходимую информацию о запросе. Это может быть что угодно: от запрошенного URL-адреса до тела POST-запроса до IP-адреса пользователя.
  • res : это объект ответа, который используется для отправки данных пользователю для данного запроса. Вы можете использовать это для отправки кода ответа HTTP 404 или для отправки обратно обработанного HTML через res.render() .
  • next : И, наконец, next параметр - это обратный вызов, чтобы сообщить Express, когда наше промежуточное ПО завершит работу. Если вы выполняете какие-либо операции ввода-вывода (например, вызовы базы данных) или тяжелые вычисления, вам, вероятно, потребуется сделать функцию асинхронной, чтобы предотвратить блокировку основного потока выполнения, и в этом случае вам придется использовать next .

Стоит отметить, что если ваше промежуточное программное обеспечение не res.end(...) вы должны вызвать next() чтобы передать управление следующему промежуточному программному обеспечению. Если вы этого не сделаете, запрос останется зависшим и истечет время ожидания.

Пример

В этом примере мы создадим промежуточное ПО, которое поможет вам автоматически переводить текст с одного языка на другой. Однако это не типичный модуль i18n, вместо него мы будем использовать Google Translate.

Допустим, вы создали приложение для чата, которое позволяет вам общаться с людьми со всего мира, и чтобы сделать его удобным, вам нужно, чтобы текст переводился автоматически. В этом случае большинство модулей i18n не будут работать, так как вам нужно предварительно перевести все строки, что мы не можем сделать, поскольку мы имеем дело с вводом пользователя.

Конечно, вы можете обрабатывать перевод на каждом из маршрутов Express или обрабатывать его за вас в промежуточном программном обеспечении, которое сохраняет ваш код маршрута более чистым и не дает вам забыть добавить перевод для каждого маршрута, который в нем нуждается.

Строки (пользовательские сообщения) поступают через REST API, поэтому нам нужно проверить все тела маршрутов API на предмет текста для перевода. Все строки, сохраняемые в базе данных в вызовах POST, будут храниться на своих родных языках, но все строки, полученные из базы данных с вызовами GET, будут переведены на язык, указанный в заголовке HTTP Accept-Language, который сопровождает запрос пользователя.

Я подумал, что мы не будем переводить все сообщения в базе данных на один и тот же язык, поскольку тогда нам придется переводить некоторые из них дважды, что ухудшает качество перевода .

Прежде всего, давайте напишем простую функцию для вызова API Google Translate:

 var googleTranslate = require('google-translate')('YOUR-API-KEY'); 
 
 var translate = function(text, lang, cb) { 
 googleTranslate.translate(text, lang, function(err, translation) { 
 if (!translation) cb(err, null); 
 cb(err, translation.translatedText); 
 }); 
 } 

Затем мы будем использовать эту функцию в нашем коде промежуточного программного обеспечения, который экспортируется в modules.export для использования приложением.

 module.exports = function(req, res, next) { 
 if (req.method === 'GET') { 
 var lang = 'en'; 
 var langs = req.acceptsLanguages(); 
 if (langs[0] !== '*') { 
 if (langs[0].length > 2) { 
                // ex: en-US 
                lang = langs[0].substring(0, 2); 
 } else { 
                // ex: en 
                lang = langs[0]; 
 } 
 } 
 
 if (lang !== res.body.lang) { 
 return translate(res.body.message, lang, function(err, translation) { 
                res.body.message = translation; 
                res.body.lang = lang; 
                next(); 
 }); 
 } 
 } 
 
 next(); 
 }; 

ПРИМЕЧАНИЕ . На самом деле это не то, как вы изменяете тело Response Я просто упрощаю его для краткости. Если вы хотите увидеть, как на самом деле изменить тело, посмотрите промежуточное программное обеспечение сжатия , которое делает это правильно. Вы должны проксировать функции res.write и res.end , чего я не делал, потому что это просто отвлекало бы от концепций, которые я пытаюсь здесь показать.

И, наконец, мы применяем промежуточное ПО к нашему приложению. Просто убедитесь, что вы вызываете функцию app.use после того, как уже объявили свои маршруты. Порядок, в котором он вызывается, - это порядок, в котором выполняется каждая функция.

Кроме того, убедитесь, что вы вызываете next() в каждом из ваших /api , иначе промежуточное ПО не будет работать.

 var expressGoogleTranslate = require('my-translation-middleware'); 
 
 var app = express(); 
 
 app.get('/api/message', function(req, res, next) {...}); 
 app.get('/api/message/all', function(req, res, next) {...}); 
 app.post('/api/message', function(req, res, next) {...}); 
 app.delete('/api/message/id', function(req, res, next) {...}); 
 
 app.use('/api', expressGoogleTranslate); 

Вот и все. Любая строка, возвращаемая в Response которая является языком, отличным от того, который принимает пользователь, будет переведена Google Translate, который определяет, на каком языке находится исходный текст.

Итак, если бы наш ответ начинался так ...

 { 
 "message": "The quick brown fox jumps over the lazy dog" 
 "lang": "en" 
 } 

... и пользователь принимает только суахили, тогда после запуска промежуточного программного обеспечения мы получим окончательный перевод, который выглядит следующим образом:

 { 
 "message": "Haraka kahawia mbweha anaruka juu ya mbwa wavivu" 
 "lang": "sw" 
 } 

Заключение

Хотя это может показаться пугающим, промежуточное ПО действительно легко создать в Express. Вы можете использовать его практически для чего угодно, независимо от того, насколько он простой или сложный.

Просто не забудьте выполнить быстрый поиск в npm того, что вы пытаетесь сделать, поскольку тонны кода уже существуют. Я уверен, что уже существует пакет, который делает то, что делает мой код перевода (и, вероятно, намного лучше).

У вас есть идеи по созданию промежуточного программного обеспечения или как улучшить мой пример выше? Дайте нам знать об этом в комментариях!

comments powered by Disqus