Jika Anda mengembangkan untuk platform node.js, maka Anda mungkin pernah mendengar tentang 
express.js . Ini adalah salah satu kerangka kerja ringan paling populer yang digunakan untuk membuat aplikasi web untuk simpul.

Penulis bahan, terjemahan yang kami terbitkan hari ini, menawarkan untuk mempelajari fitur-fitur struktur internal kerangka kerja ekspresinya melalui analisis kode sumbernya dan pertimbangan contoh penggunaannya. Dia percaya bahwa studi tentang mekanisme yang mendasari perpustakaan open source populer berkontribusi untuk pemahaman yang lebih mendalam tentang mereka, menghilangkan tirai "misteri" dari mereka dan membantu untuk membuat aplikasi yang lebih baik berdasarkan pada mereka.
Anda mungkin merasa nyaman untuk menjaga kode sumber ekspres berguna saat membaca materi ini. 
Versi ini digunakan di sini. Anda dapat membaca artikel ini tanpa membuka kode kilat, karena di sini, di mana pun sesuai, bagian kode dari perpustakaan ini diberikan. Di tempat-tempat di mana kode disingkat, komentar dari formulir 
// ...Contoh dasar menggunakan express
Untuk mulai dengan, mari kita lihat "Hello World!" Tradisional dalam pengembangan teknologi komputer baru - sebuah contoh. Ini dapat ditemukan di situs web resmi kerangka kerja, ini akan berfungsi sebagai titik awal dalam penelitian kami.
 const express = require('express') const app = express() app.get('/', (req, res) => res.send('Hello World!')) app.listen(3000, () => console.log('Example app listening on port 3000!')) 
Kode ini memulai server HTTP baru pada port 3000 dan mengirimkan 
Hello World! untuk permintaan yang diterima pada 
GET / rute. Jika Anda tidak merinci, maka kami dapat membedakan empat tahap dari apa yang terjadi, yang dapat kami analisis:
- Buat aplikasi ekspres baru.
- Buat rute baru.
- Memulai server HTTP pada nomor port yang ditentukan.
- Memproses permintaan masuk ke server.
Membuat aplikasi ekspres baru
Perintah 
var app = express() memungkinkan Anda membuat aplikasi ekspres baru. Fungsi 
createApplication dari file 
lib / express.js adalah fungsi default yang diekspor; kita yang mengaksesnya dengan memanggil fungsi 
express() . Berikut adalah beberapa hal penting yang harus Anda perhatikan:
 // ... var mixin = require('merge-descriptors'); var proto = require('./application'); // ... function createApplication() { //    ,     . //     : `function(req, res, next)` var app = function(req, res, next) {   app.handle(req, res, next); }; // ... //  `mixin`    `proto`  `app` //     -  `get`,     . mixin(app, proto, false); // ... return app; } 
Objek 
app dikembalikan dari fungsi ini adalah salah satu objek yang digunakan dalam kode aplikasi kami. Metode 
app.get ditambahkan menggunakan fungsi 
mixin dari pustaka 
gabungan-deskriptor , yang bertanggung jawab untuk menetapkan metode 
app yang dinyatakan dalam 
proto . Objek 
proto sendiri diimpor dari 
lib / application.js .
Buat rute baru
Sekarang mari kita lihat 
kode yang bertanggung jawab untuk membuat metode 
app.get dari contoh kita.
 var slice = Array.prototype.slice; // ... /** *   `.VERB(...)` `router.VERB(...)`. */ // `methods`    HTTP, (  ['get','post',...]) methods.forEach(function(method){ //    app.get app[method] = function(path){   //     //          var route = this._router.route(path);   //        route[method].apply(route, slice.call(arguments, 1));   //   `app`,          return this; }; }); 
Sangat menarik untuk dicatat bahwa, di samping fitur semantik, semua metode yang menerapkan tindakan HTTP, seperti 
app.get , 
app.post , 
app.put dan sejenisnya, dalam hal fungsionalitas, dapat dianggap sama. Jika Anda menyederhanakan kode di atas, menguranginya menjadi implementasi hanya satu metode 
get , Anda mendapatkan sesuatu seperti berikut:
 app.get = function(path, handler){ // ... var route = this._router.route(path); route.get(handler) return this } 
Meskipun fungsi di atas memiliki 2 argumen, ini mirip dengan 
app[method] = function(path){...} fungsi 
app[method] = function(path){...} . Argumen kedua, 
handler , diperoleh dengan memanggil 
slice.call(arguments, 1) .
Singkatnya, 
app.<method> hanya menyimpan rute di router aplikasi menggunakan metode 
route , dan kemudian melewati 
handler ke 
route.<method> .
Metode 
route() router dideklarasikan di 
lib / router / index.js :
 // proto -     `_router` proto.route = function route(path) { var route = new Route(path); var layer = new Layer(path, {   sensitive: this.caseSensitive,   strict: this.strict,   end: true }, route.dispatch.bind(route)); layer.route = route; this.stack.push(layer); return route; }; 
Tidak mengejutkan, deklarasi metode 
route.get di 
lib / router / route.js mirip dengan deklarasi 
app.get :
 methods.forEach(function (method) { Route.prototype[method] = function () {   // `flatten`   ,  [1,[2,3]],      var handles = flatten(slice.call(arguments));   for (var i = 0; i < handles.length; i++) {     var handle = handles[i];         // ...     //   ,  ,    Layer,     //            var layer = Layer('/', {}, handle);     // ...     this.stack.push(layer);   }   return this; }; }); 
Setiap rute dapat memiliki beberapa penangan, atas dasar setiap penangan, variabel tipe 
Layer dibangun, yang merupakan lapisan pemrosesan data, yang kemudian masuk ke stack.
Objek Lapisan
Baik 
_router dan 
route menggunakan objek bertipe 
Layer . Untuk memahami esensi dari objek semacam itu, mari kita lihat 
konstruktornya :
 function Layer(path, options, fn) { // ... this.handle = fn; this.regexp = pathRegexp(path, this.keys = [], opts); // ... } 
Saat membuat objek bertipe 
Layer mereka diberi jalur, parameter tertentu, dan fungsi. Dalam kasus router kami, fungsi ini adalah 
route.dispatch (kami akan membicarakan lebih lanjut di bawah ini, secara umum, ini dirancang untuk mengirimkan permintaan ke rute yang terpisah). Dalam kasus rute itu sendiri, fungsi ini adalah fungsi handler yang dideklarasikan dalam kode contoh kita.
Setiap objek bertipe 
Layer memiliki metode 
handle_request , yang bertanggung jawab untuk mengeksekusi fungsi yang diteruskan ketika objek diinisialisasi.
Ingat apa yang terjadi ketika membuat rute menggunakan metode 
app.get :
- Sebuah rute dibuat di router aplikasi ( this._router).
- Metode rute dispatchditugaskan sebagai metode handler dari objekLayersesuai, dan objek ini didorong ke stack router.
- Penangan permintaan diteruskan ke objek Layersebagai metode penangan, dan objek ini didorong ke tumpukan rute.
Akibatnya, semua penangan disimpan di dalam instance 
app dalam bentuk objek dari tipe 
Layer yang ada di dalam route stack, yang metode 
dispatch ditugaskan ke objek 
Layer yang ada di stack router:
Lapisan objek pada stack router dan stack routePermintaan HTTP yang masuk diproses sesuai dengan logika ini. Kami akan membicarakannya di bawah.
Startup server HTTP
Setelah mengkonfigurasi rute, Anda harus memulai server. Dalam contoh kita, kita beralih ke metode 
app.listen , meneruskannya nomor port dan fungsi panggilan balik sebagai argumen. Untuk memahami fitur-fitur metode ini, kita dapat merujuk ke file 
lib / application.js :
 app.listen = function listen() { var server = http.createServer(this); return server.listen.apply(server, arguments); }; 
app.listen hanya pembungkus di sekitar 
http.createServer . Sudut pandang seperti itu masuk akal, karena jika Anda mengingat apa yang kita bicarakan di awal, 
app hanyalah sebuah fungsi dengan 
function(req, res, next) {...} tanda tangan 
function(req, res, next) {...} , yang kompatibel dengan argumen yang diperlukan untuk 
http.createServer (tanda tangan dari metode ini adalah 
function (req, res) {...} ).
Setelah menyadari bahwa, pada akhirnya, segala sesuatu yang diekspresikan.
Pemrosesan permintaan HTTP
Sekarang kami tahu bahwa 
app hanyalah penangan permintaan, kami akan mengikuti jalur yang dilewati permintaan HTTP di dalam aplikasi ekspres. Jalan ini membawanya ke pawang yang dinyatakan oleh kami.
Pertama, permintaan pergi ke fungsi 
createApplication ( 
lib / express.js ):
 var app = function(req, res, next) {   app.handle(req, res, next); }; 
Kemudian masuk ke metode 
app.handle ( 
lib / application.js ):
 app.handle = function handle(req, res, callback) { // `this._router` -  ,    ,  `app.get` var router = this._router; // ... //     `handle` router.handle(req, res, done); }; 
Metode 
router.handle dideklarasikan di 
lib / router / index.js :
 proto.handle = function handle(req, res, out) { var self = this; //... // self.stack -  ,      // Layer (  ) var stack = self.stack; // ... next(); function next(err) {   // ...   //        var path = getPathname(req);   // ...   var layer;   var match;   var route;   while (match !== true && idx < stack.length) {     layer = stack[idx++];     match = matchLayer(layer, path);     route = layer.route;     // ...     if (match !== true) {       continue;     }     // ...      HTTP,       }  // ...      // process_params    ,          self.process_params(layer, paramcalled, req, res, function (err) {     // ...     if (route) {       //       `layer.handle_request`       //         `next`       //  ,   `next`     ,              //  ,   `next`   ,            return layer.handle_request(req, res, next);     }     // ...   }); } }; 
Singkatnya, fungsi 
router.handle melewati semua lapisan pada stack sampai menemukan yang cocok dengan jalur yang ditentukan dalam permintaan. Kemudian, metode layer 
handle_request akan dipanggil, yang akan menjalankan fungsi handler yang telah ditentukan. Fungsi pengendali ini adalah metode rute 
dispatch , yang dideklarasikan di 
lib / route / route.js :
 Route.prototype.dispatch = function dispatch(req, res, done) { var stack = this.stack; // ... next(); function next(err) {   // ...   var layer = stack[idx++];   // ...    layer.handle_request(req, res, next);   // ... } }; 
Sama seperti dalam kasus router, selama pemrosesan setiap rute, lapisan yang rute ini telah disebutkan dan metode 
handle_request mereka yang menjalankan metode layer handler 
handle_request . Dalam kasus kami, ini adalah penangan permintaan, yang dinyatakan dalam kode aplikasi.
Di sini, akhirnya, permintaan HTTP masuk ke area kode aplikasi kita.
Jalur permintaan dalam aplikasi ekspresRingkasan
Di sini kami hanya memeriksa mekanisme dasar dari perpustakaan express.js, yang bertanggung jawab atas pengoperasian server web, tetapi perpustakaan ini juga memiliki banyak fitur lainnya. Kami tidak berhenti pada pemeriksaan yang diminta melalui permintaan sebelum mereka mencapai penangan, kami tidak berbicara tentang metode pembantu yang tersedia ketika bekerja dengan variabel 
res dan 
req . Dan akhirnya, kami tidak menyentuh salah satu fitur ekspres yang paling kuat. Ini terdiri dari penggunaan middleware, yang dapat ditujukan untuk menyelesaikan hampir semua masalah - mulai dari penguraian permintaan hingga penerapan sistem otentikasi lengkap.
Kami berharap materi ini membantu Anda memahami fitur utama perangkat ekspres, dan sekarang, jika perlu, Anda dapat memahami semua hal lainnya dengan menganalisis secara independen bagian-bagian dari kode sumber perpustakaan ini yang menarik minat Anda.
Pembaca yang budiman! Apakah Anda menggunakan express.js?
