Server là nơi tiếp nhận những yêu cầu và phản hồi lại những yêu cầu đó cho khách hàng. Nơi để tiếp nhận đó chính ra route. Route tạo ra những nơi tiếp nhận cho từng yêu cầu khác nhau. Cùng mình tìm hiểu route trong Express ngay bây giờ !!!
Giới thiệu
Router là phương thức khai báo để đáp lại requrest từ client, nó có thể hiểu tương tự như một Request mapping. Nói đơn giản hơn là định nghĩa URL cho trang web mà người dùng sẽ tương tác. Một số định nghĩa router thường dùng :
Định nghĩa cho trường hợp người dùng nhập URL cơ bản : http://localhost:3000/
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
Sử dụng nodemon để không phải restart server bằng tay mỗi khi thay đổi code
Install nodemon bằng npm
npm install --save-dev nodemon
Update code trong file
package.json
"scripts": { "start": "nodemon my_file.js" },
sau đó chạy command:
npm run start
Cấu trúc định tuyến cơ bản
Trong express.js định tuyến có cấu trúc như sau
app.METHOD(Path, Handler...)
trong đó
- app: là 1 instance của express
- METHOD: là một HTTP method
- Path: là một đường dẫn trên máy chủ
- Handler : là một function sẽ thực thi khi một route được trùng khớp
Giải thích
- Handler : có thể có một hoặc nhiều function
- Một route được xác định bằng Path (đường dẫn) và request method.
- Khái niệm route trùng khớp là chỉ việc một người dùng thực hiện request với Path (đường dẫn) và Method trùng khớp với định nghĩa trong route.
Route methods
Express hỗ trợ rất nhiều loại HTTP methods khác nhau, bao gồm :
get, post, put, head, delete, options, trace, copy, lock, mkcol, move, purge, unlock, report, mkactivity, checkout, merge, m-search, notify, subscribe, unsubscribe, patch and searc
Trong đó sử dụng nhiều nhất là: Get, Post, Put, Head, Delete và Options
khai báo đơn giản như sau:
// GET method route
app.get('/', function (req, res) {
res.send('GET request to the homepage')
})
// POST method route
app.post('/', function (req, res) {
res.send('POST request to the homepage')
})
Có một method đặc biệt là app.all()
. dùng để load middleware tạo một đường dẫn cho tất cả các http request methods. Ví dụ: trình xử lý sau được thực thi cho các yêu cầu đến tuyến “/ secret” cho dù sử dụng GET, POST, PUT, DELETE hoặc bất kỳ phương thức yêu cầu HTTP nào khác
app.all('/secret', function (req, res, next) {
console.log('Accessing the secret section ...')
next() // pass control to the next handler
})
Route paths
Đây là phần trọng tâm của bài học hôm nay, route path có thể là một chuỗi thông thường (String) hoặc là một chuỗi có ký hiệu biểu thức chính quy (string patterns) hoặc là một biểu thức chính quy (regular expressions). Ví dụ
/users/nghuuquyen : là một đường dẫn thông thường
app.get('/users/nghuuquyen', function(req, res) { //Do something. });
/users/user/* : là một đường dẫn với ký hiệu * biểu diễn cho một chuỗi bất kỳ. Ký hiệu * ở đây nói lên là route trên khớp với mọi đường dẫn bắt đầu với /users/.
app.get('/users/*', function(req, res) { // Do something. });
/^[a-zA-Z0-9]{5,15}$/ : là một đường dẫn có dạng biểu thức chính quy (regular expression). Route này sẽ khớp với mọi đường dẫn kết thúc với đuôi là cool. Ví dụ YOUARESOcool sẽ khớp, nhưng YOUTOOCool thì sẽ không vì khác ký tự ‘C’.
app.get(/.*cool$/, function(req, res) { // Do something. });
Và một số đường dẫn theo khuôn mẫu (String pattern) các bạn có thể tham khảo thêm. Biết đâu sẽ áp dụng vào dự án của chúng ta. Chớ mình là mình ít dụng tới lắm =]]].
Sử dụng
?
. Có hay không ký tự liền trước?
đều được.app.get('/ab?cd', function (req, res) { res.send('ab?cd') })
cho phép
acd
vàabcd
.Sử dụng
+
. Thêm bao nhiêu kí tự liền trước nó vẫn phù hợpapp.get('/ab+cd', function (req, res) { res.send('ab+cd') })
cho phép
abcd
,abbbcd
….Sử dụng
*
. Tại vị trí (*) thay thế bằng bất cứ ký tự, hay chuỗi hoặc số đều đượcapp.get('/ab*cd', function (req, res) { res.send('ab*cd') })
abcd, abxcd, abRANDOMcd, ab123cd
…Sử dụng
(...)
. Kí tự bên trong ngoặc có hay không đều được.app.get('/ab(cd)?e', function (req, res) { res.send('ab(cd)?e') })
/abe, /abcde
Sử dụng
../
. Cho phép những đường dẫn có url thỏa những ký tự đã được khai báo, phía sau nó là gì cũng được.app.get(/a/, function (req, res) { res.send('/a/') })
path nào bắt đầu bằng kí tự a đều thỏa.
a, ab, arandom
, …
Route parameters
Route parameters là những vị trí trên url được đánh dấu bằng cách đặt tên, mục đích để lấy giá trị tương ứng ra sử dụng. Tất cả cá giá trị đối số sẽ được đặt vào đối tượng 8 trong thuộc tính params. Với tên thuộc tính trùng khớp với từ khóa được xác định trên URL.
// Route path: /users/
// Request URL: http://localhost:3000/users/34/books/8989
// req.params: { "userId": "34", "bookId": "8989" }
app.route('/users/:userId/books/:bookId', function(req, res) {
res.send(req.params);
});
Lưu ý, tên của tham số phải thỏa ([A-Za-z0-9_]).
Một số trường hợp khác khi làm việc vói -
và .
.
Route path: /flights/:from-:to
Request URL: http://localhost:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }
Route path: /plantae/:genus.:species
Request URL: http://localhost:3000/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }
Nâng cao hơn một xíu, ta sẽ áp dụng những biểu thức chính quy cho param này.:userId(^[A-Za-z0-9.-_]{8,30}+$)
: Lúc này nếu bạn nhập vào một đường dẫn có đối số :userId ngắn hơn 8 hoặc dài hơn 30 ký tự thì route trên sẽ không nhận, hoặc chứa ký tự khác dấu ., _ -
, thì route cũng không nhận. Từ đó hạn chế được việc query một username bị sai quy tắc và lại an toàn tránh tấn công SQL injection.
Route handlers
Đơn giản là một hoặc nhiều function sẽ được gọi khi một route trùng khớp để đáp ứng một yêu cầu nào đó. Lưu ý các handler sẽ được gọi đúng theo thứ tự truyền vào. Ví dụ
app.get(‘/user’, [a, b]);
thì a sẽ gọi trước b. Chú ý là để b được gọi thì trong a phải gọi hàm next(). Ví dụ
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
var cb2 = function (req, res) {
res.send('Hello from C!')
}
app.get('/c', [cb0, cb1, cb2]);
Nếu truyền nhiều tham số vào các hàm METHOD, thì tham số thứ 2 là middleware, các tham số sau mới là handlers.
Và tất nhiên, tham số thứ 2 chúng ta vẫn có thể truyền vào 1 array.
var cb0 = function (req, res, next) {
console.log('CB0')
next()
}
var cb1 = function (req, res, next) {
console.log('CB1')
next()
}
app.get('/example/d', [cb0, cb1], function (req, res, next) {
console.log('the response will be sent by the next function ...')
next()
}, function (req, res) {
res.send('Hello from D!')
})
Túm cái váy lại: những function nào gọi next() đều là middleware đó bạn, nếu nó next() thì mới cho phép request đi tiếp, nếu không sẽ đứng lại tại đố và response gì đó về phía user và kết thúc.
app.route()
Đây là một cách định nghĩa route rõ ràng hơn, mới được hỗ trợ trong các phiên bản mới. Ví dụ thay vì bạn định nghĩa như sau.
function doGet(req, res, next) {
// something ...
}
function doPost(req, res, next) {
// something ...
}
function doPut(req, res, next) {
// something ...
}
app.get('/users/:user', doGet);
app.post('/users/:user', doPost);
app.put('/users/:user', doPut);
thì áp dụng app.route chúng ta có thể làm ngắn gọn như sau
function doGet(req, res, next) {
// something ...
}
function doPost(req, res, next) {
// something ...
}
function doPut(req, res, next) {
// something ...
}
app.route('/users/:user')
.get(doGet)
.post(doPost)
.put(doPut);
Express.Router
Đây là một điều thú vị được cập nhận trong phiên bản mới của Express, giúp chúng ta có thể module hóa công việc định tuyến thành cái module nhỏ có thể sử dụng lại.
Ví dụ mình định nghĩa một module route có khả năng trả về thời gian hiện tại khi truy cập /time
như dưới đây . Mình để trong file là time.server.routes.js
var express = require('express')
var router = express.Router()
router.get('/time', function (req, res) {
res.send(Date.now());
})
module.exports = router
Và ta sẽ sử dụng router
này trong file app.js
var timeRoutes = require('./routes/time.server.routes');
// ...
app.use('/helpers', timeRoutes);
Như trên ta có thể truy cập để lấy thời gian ở route là GET /helper/time
. Rất tiện đúng không nào.
Kết luận
Qua bài học này, mình đã giới thiệu cho tất cả các bạn các kỹ thuật cơ bản và cả nâng cao của Routing.
Các bạn cần nắm kỹ các kiến thức như sau:
- Hiểu rõ về Routing và các định nghĩa của nó.
- Biết được Express cung cấp cho ta những tính năng gì để hỗ trợ cho việc Routing.
- Nắm được ý tưởng về mô hình MVC.
- Thấy được kiến trúc thực tế của một trang website xây dựng theo mô hình MVC.
Nguồn tham khảo:
Rất mong được sự ủng hộ của mọi người để mình có động lực ra những bài viết tiếp theo.
{\__/}
( ~.~ )
/ > ♥️ I LOVE YOU 3000
JUST DO IT!