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
dispatch
ditugaskan sebagai metode handler dari objek Layer
sesuai, dan objek ini didorong ke stack router. - Penangan permintaan diteruskan ke objek
Layer
sebagai 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?
