Jak napsat Middleware Express.js

Úvod

Přemýšleli jste někdy, co se děje v rámci veškerého middlewaru Express.js, který přidáváte do své webové aplikace? Ve skutečnosti je docela působivé, jaký druh funkcí můžete přidat do svých aplikací pomocí jediného řádku kódu nebo několika:

// requires...

var app = express();

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

Poslední tři řádky výše pro nás zpracovávají docela dost funkcí webové aplikace. První app.use() volání říká Expressu, kde se nacházejí naše statické soubory a jak je vystavit, cookieParser('sekret') middleware zpracovává veškerou analýzu souborů cookie (se šifrováním) a poslední z nich automaticky komprimuje všechna naše data těla HTTP. Není to špatné za pouhé tři řádky kódu.

Tyto middleware jsou ve vaší průměrné webové aplikaci docela typické, ale můžete najít některé, které umí víc než jen standardní kompresi dat nebo analýzu souborů cookie. Vezměte si například tyto:

  • helma:Pomáhá zabezpečit vaši aplikaci nastavením různých záhlaví HTTP
  • express-simple-cdn:Snadné použití CDN pro svá statická díla
  • join-io:Připojujte soubory za běhu, abyste snížili počet požadavků HTTP
  • passport:Přidá k vybraným trasám ověření uživatele

A zde je mnohem větší seznam middlewaru, který byste mohli chtít použít.

Nyní, když jste viděli několik příkladů, zde je téměř vše, co s tím můžete dělat:

  • Spouštět jakýkoli kód, včetně asynchronního kódu
  • Proveďte změny nebo doplnění objektů požadavku a odpovědi
  • Ukončit cyklus žádost-odpověď
  • Zavolejte další middleware v zásobníku

S nekonečnými možnostmi jsem si jistý, že máte nějaké vlastní nápady, které byste chtěli vytvořit, takže ve zbytku tohoto článku vám budu ukazovat, jak napsat svůj vlastní middleware. Existuje několik různých typů middlewaru, které můžete napsat (aplikace, router, zpracování chyb atd.), ale v tomto článku se zaměříme pouze na aplikační úroveň.

Základy

Middleware lze považovat téměř za expresní cestu. Berou stejné parametry a všechno, ale na rozdíl od normálních tras není nutné zadat cestu URL pro middleware. Dva největší rozdíly jsou v tom, jak se s cestou zachází a kdy se nazývá.

Zadaná cesta je považována za prefix, takže pokud jste měli něco jako app.use('/api', ...) , pak váš middleware poběží, pokud /api se nazývá a pokud /api/users je nazýván. To se liší od tras, kde se cesta musí přesně shodovat.

Cestu URL lze z app.use() vynechat zavolejte, pokud chcete, aby se váš kód spouštěl pro všechny požadavky, jinak můžete zadat cestu a nechat svůj kód spouštět pouze tehdy, když je tato trasa (a všechny její podcesty) požadována. To může být užitečné například pro přidání ověřování pouze do několika daných tras.

Jednoduchý middleware může vypadat takto:

var app = express();

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

Zatímco obsluha trasy vypadá takto:

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

Vidět? Jsou to v podstatě stejné věci, takže psaní těchto funkcí by vám mělo být docela známé.

Použité parametry jsou:

  • req :Objekt obsahující všechny relevantní informace o požadavku. Může to být cokoli od požadované adresy URL přes tělo požadavku POST až po IP adresu uživatele.
  • res :Toto je objekt odpovědi, který se používá k odeslání dat zpět uživateli pro daný požadavek. Můžete to použít k odeslání zpět kódu odpovědi HTTP 404 nebo k odeslání zpět vykresleného HTML přes res.render() .
  • next :A nakonec next Parametr je zpětné volání, které Expressu řekne, že náš middleware skončil. Pokud provádíte jakékoli IO (například databázová volání) nebo náročné výpočty, budete pravděpodobně muset funkci nastavit jako asynchronní, abyste zabránili blokování hlavního spouštěcího vlákna, v takovém případě budete muset použít next .

Stojí za zmínku, že pokud váš middleware neukončí cyklus žádost-odpověď s res.end(...) pak musíte volejte next() předat řízení dalšímu middlewaru. Pokud tak neučiníte, požadavek zůstane viset a vyprší časový limit.

Příklad

V tomto příkladu vytvoříme middleware, který vám pomůže automaticky překládat text mezi jazyky. Toto však není typický modul i18n, místo toho budeme používat Překladač Google.

Řekněme, že jste vytvořili chatovací aplikaci, která vám umožní mluvit s lidmi z celého světa, a aby to bylo bezproblémové, potřebujete, aby byl text automaticky přeložen. V tomto případě použití by většina modulů i18n nefungovala, protože musíte předem přeložit všechny řetězce, což nemůžeme udělat, protože se zabýváme uživatelským vstupem.

Jistě, můžete překlad zpracovat v každé ze svých expresních tras, nebo můžete si to nechat zařídit v middlewaru, který udrží váš kód trasy čistší a zabrání vám, abyste zapomněli přidat překlad ke každé trase, která to potřebuje.

Řetězce (uživatelské zprávy) přicházejí přes REST API, takže budeme muset zkontrolovat všechna těla tras API, aby se přeložil text. Všechny řetězce ukládané do databáze ve voláních POST budou zachovány v jejich rodných jazycích, ale všechny řetězce načítané z databáze pomocí volání GET budou přeloženy do jazyka uvedeného v hlavičce HTTP Accept-Language, která doprovází požadavek uživatele.

Usoudil jsem, že neuděláme všechny zprávy v databázi ve stejném jazyce, protože některé z nich budeme muset přeložit dvakrát, což snižuje kvalitu překladu.

Zdarma e-kniha:Git Essentials

Prohlédněte si našeho praktického průvodce učením Git s osvědčenými postupy, průmyslově uznávanými standardy a přiloženým cheat sheetem. Přestaňte používat příkazy Google Git a skutečně se naučte to!

Nejprve si napíšeme jednoduchou funkci pro volání rozhraní Google Translate API:

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);
	});
}

Potom tuto funkci použijeme v našem middlewarovém kódu, který je exportován v modules.export pro použití aplikací.

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();
};

POZNÁMKA :Toto není způsob, jakým upravujete Response tělo. Jen to pro stručnost zjednoduším. Pokud chcete vidět, jak skutečně upravit tělo, pak se podívejte na kompresní middleware, který to dělá správně. Musíte použít proxy res.write a res.end funkcí, což jsem neudělal, protože by to jen odvádělo pozornost od pojmů, které se zde snažím ukázat.

A nakonec aplikujeme middleware na naši aplikaci. Jen se ujistěte, že voláte app.use funkce po již jste deklarovali své trasy. Pořadí, ve kterém je volána, je pořadí, ve kterém běží jednotlivé funkce.

Nezapomeňte také zavolat na číslo next() v každém z vašich /api trasy, jinak middleware nepoběží.

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);

A to je všechno. Jakýkoli řetězec vrácený v Response tělo, které je v jiném jazyce, než jaký uživatel přijímá, bude přeloženo Překladačem Google, který zjistí, v jakém jazyce je zdrojový text.

Takže pokud naše odpověď začala vypadat takto...

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

...a uživatel přijímá pouze svahilštinu, poté po spuštění middlewaru získáme konečný překlad, který vypadá takto:


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

Závěr

Ačkoli to může znít hrozivě, middleware je skutečně snadné vytvoření v Express. Můžete jej použít téměř na cokoli, bez ohledu na to, jak jednoduché nebo složité to je.

Nezapomeňte rychle vyhledat na npm cokoli, co se snažíte vytvořit, protože tuny kódu jsou již venku. Jsem si jistý, že už existuje balíček, který dělá to, co můj překladový kód (a pravděpodobně mnohem lepší).

Máte nějaké nápady na vytvoření middlewaru nebo jak vylepšit můj výše uvedený příklad? Dejte nám vědět v komentářích!