[ExpressJS] Bài 1 – Làm Quen Với ExpressJS

Như vậy là chúng ta lại bắt đầu một Sub-Series mới của Tự Học Lập Trình Web Một Cách Thật Tự Nhiên để tìm hiểu về một framework có tên là ExpressJS. Đây là một framework rất phổ biến dành cho các ứng dụng web trên nền NodeJS – và sẽ giúp đỡ chúng ta

Như vậy là chúng ta lại bắt đầu một Sub-Series mới của Tự Học Lập Trình Web Một Cách Thật Tự Nhiên để tìm hiểu về một framework có tên là ExpressJS. Đây là một framework rất phổ biến dành cho các ứng dụng web trên nền NodeJS – và sẽ giúp đỡ chúng ta xây dựng phần mềm server thuận lợi hơn với nhiều lớp công cụ trừu tượng và cách sử dụng đơn giản.

Trước khi bắt đầu bước vào phần nội dung chính của bài viết, chúng ta sẽ cùng nhìn lại code server đơn giản mà chúng ta đã viết trước đó. Ở đây chúng ta vẫn sẽ sử dụng lại cấu trúc thư mục như cũ với các tệp HTML, CSS, và JS giả định đã được tạo ra trước đó. Các thành phần tạo ra bởi npm thì mình sẽ không liệt kê ở đây, tuy nhiên thì chúng ta đều đã biết là project khởi đầu của mình đã init xong xuôi rồi. Chúng ta chỉ việc cài đặt thêm ExpressJS để viết code thử và học kiến thức mới thôi. 😄

[nodejs-blog]
   |
   +---[static]
   |      |
   |      +---[asset]
   |      |      |
   |      |      +---style.css
   |      |      +---main.js
   |      |
   |      +---[post]
   |      |      |
   |      |      +---an-article.html
   |      |      +---another-article.html
   |      |
   |      +---index.html
   |      +---oops.html
   |
   +---route.js
   +---server.js
   +---test.js
const textType ={
   html:'text/html',
   css:'text/css',
   js:'text/javascript',get(url){if(url.endsWith('.html'))return textType.html;elseif(url.endsWith('.css'))return textType.css;elseif(url.endsWith('.js'))return textType.js;elsereturn'';}};// textType

exports.handleHomeRequest=function(request, response){var fsPromises =require('fs/promises');

   fsPromises.readFile('static'+'/index.html').then(function(data){
         response.setHeader('content-type', textType.html);
         response.writeHead(200);
         response.end(data);}).catch(function(error){
         console.error(error);});};// handleHomeRequest

exports.handlePostRequest=function(request, response){var fsPromises =require('fs/promises');

   fsPromises.readFile('static'+ request.url).then(function(data){
         response.setHeader('content-type','text/html');
         response.writeHead(200);
         response.end(data);}).catch(function(error){
         console.error(error);handleOopsRequest(request, response);});};// handlePostRequest

exports.handleAssetRequest=function(request, response){var fsPromises =require('fs/promises');

   fsPromises.readFile('static'+ request.url).then(function(data){var contentType = textType.get(request.url);
         response.setHeader('content-type', contentType);
         response.writeHead(200);
         response.end(data);}).catch(function(error){
         console.error(error);});};// handleAssetRequest

exports.handleOopsRequest=function(request, response){var fsPromises =require('fs/promises');

   fsPromises.readFile('static'+'/oops.html').then(function(data){
         response.setHeader('content-type', textType.html);
         response.writeHead(404);
         response.end(data);}).catch(function(error){
         console.error(error);});};// handleOopsRequest
/* Creating a server */const http =require('http');consthandleRequest=function(request, response){var route =require('./route.js');if(request.url =='/')
      route.handleHomeRequest(request, response);elseif(request.url.startsWith('/post'))
      route.handlePostRequest(request, response);elseif(request.url.startsWith('/asset'))
      route.handleAssetRequest(request, response);else
      route.handleOopsRequest(request, response);};// handleRequestconst server = http.createServer(handleRequest);/* Start running server */const port =3000;const hostname ='127.0.0.1';constcallback=function(){
   console.log('Server is running at...');
   console.log('http://'+ hostname +':'+ port +'/');};// callback

server.listen(port, hostname, callback);
// xóa nội dung để làm quen với ExpressJS
<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Homepage</title><linkrel="stylesheet"href="/asset/style.css"></head><body><h1>Homepage</h1><scriptsrc="/asset/main.js"></script></body></html>
<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Oops ! Not-Found</title><linkrel="stylesheet"href="/asset/style.css"></head><body><h1>Oops ! Not-Found</h1><scriptsrc="/asset/main.js"></script></body></html>
<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>An Article</title><linkrel="stylesheet"href="/asset/style.css"></head><body><h1>An Article</h1><scriptsrc="/asset/main.js"></script></body></html>
<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Another Article</title><linkrel="stylesheet"href="/asset/style.css"></head><body><h1>Another Article</h1><scriptsrc="/asset/main.js"></script></body></html>
console.log('Client-side JavaScript');
h1{font-size: 90px;line-height: 1.5;text-align: center;}

Cài đặt và sử dụng ExpressJS cơ bản

Giống với các package khác mà chúng ta đã thử cài đặt từ npm, việc tiến hành cài đặt ExpressJS cho project hiện hành được thực hiện bằng một dòng lệnh cơ bản.

CMD | Terminal

npm install express --save

Và như vậy là chúng ta đã có thể viết code để sử dụng thử ExpressJS giống như lần đầu tiên khởi tạo một server trên nền NodeJS. Mà thực ra chúng ta không viết, là copy/paste về từ trang chủ của ExpressJS thôi. 😄

/* Creating server */const express =require('express')const server =express()/* Adding a route */var path ='/'

server.get(path,function(request, response){
   response.send('Hello World!')})/* Start running server */var port =3000

server.listen(port,function(){
   console.log('Server is running at...')
   console.log(`http://127.0.0.1:${port}`)})

Bắt đầu chạy thử code Hello World được cung cấp bởi ExpressJS.com.

CMD | Terminal

npm test

Tuyệt.. mọi thứ đã hoạt động tốt giống như ExpressJS quảng cáo. 😄

Ở đây chúng ta có thể thấy đặc điểm quan trọng đầu tiên trong code ví dụ của ExpressJS cung cấp đó là… không có dấu chấm phẩy ; nào cả. 😄 Về việc JavaScript không bắt buộc phải sử dụng các dấu ; để kết thúc câu lệnh thì chúng ta đã đề cập tới từ bài viết đầu tiên giới thiệu về JavaScript rồi. Tuy nhiên chúng ta cũng đã quy ước là sẽ giữ thói quen sử dụng nó trong một thời gian cho đến khi cảm thấy quen thuộc hơn với JavaScript. Và bây giờ thì ExpressJS vừa mới nhắc chúng ta là có thể ngưng sử dụng các dấu ; được rồi. 😄

Đối với code khởi tạo server đơn giản thì hiển nhiên chúng ta chưa thể nhìn thấy được nhiều sự khác biệt giữa code Hello World không có ExpressJS và code Hello World mà chúng ta vừa mới copy/paste từ trang chủ của ExpressJS. Ở đây chúng ta chỉ nhận ra một chi tiết khác biệt nho nhỏ – đó là đoạn server.get() chắc chắn là có ý nghĩa tương đương với đoạn code mà chúng ta truyền hàm xử lý yêu cầu handleRequest vào phương thức http.createServer của code cũ.

Tuy nhiên ở đây server.get() nhận vào thêm một tham số path chỉ đường dẫn nhận diện từ yêu cầu được gửi tới. Và hàm xử lý yêu cầu được truyền vào sẽ chỉ được thực thi khi yêu cầu gửi tới phù hợp với path mà chúng ta truyền vào phương thức server.get(). Như vậy là chúng ta không phải khởi đầu với một hàm handleRequest tiếp nhận tất cả các kiểu reuqest truyền tới và sau đó lại phải thực hiện phân tích để chia tác vụ về các hàm xử lý phụ. Nếu vậy có lẽ ExpressJS sẽ cho phép chúng ta tạo ra thêm những chu trình xử lý route khác với cách thức tương tự như cái route dành cho trang chủ trong code ví dụ vừa rồi.

/* Creating server */const express =require('express')const server =express()/* Adding a route */

server.get('/',function(request, response){
   response.send('Bạn vừa yêu cầu xem Trang Chủ')})

server.get('/post',function(request, response){
   response.send('Bạn vừa yêu cầu xem Bài Viết')})/* Start running server */

server.listen(3000,function(){
   console.log('Server is running at...')
   console.log(`http://127.0.0.1:${port}`)})

Thật tuyệt… Như vậy là chúng ta không cần phải thực hiện thao tác phân tích đường dẫn yêu cầu ở một hàm tiếp nhận request tổng bộ rồi ủy thác công việc tới hàm xử lý phù hợp ở cấp thấp hơn. Tất cả những gì chúng ta cần làm đó là truyền các cặp đường dẫn/hàm xử lý tương ứng vào các câu lệnh server.get(path, handler).

Tuy nhiên đó vẫn chưa phải là tất cả những gì mà ExpressJS có thể giúp đỡ chúng ta thay đổi code server đơn giản mà chúng ta đã có trước đó. Bây giờ chúng ta sẽ thử gửi trả lại các tệp HTML tĩnh tương ứng với các yêu cầu.

/* Creating server */const express =require('express')const server =express()/* Adding routes */var staticPath = __dirname +'/static'

server.get('/',function(request, response){
   response.sendFile(staticPath +'/index.html')})

server.get('*',function(request, response){
   response.sendFile(staticPath + request.originalUrl)})/* Start running server */

server.listen(3000,function(){
   console.log('Server is running at...')
   console.log(`http://127.0.0.1:${port}`)})

Thao tác gửi trả một tệp tĩnh cũng là một trong số những thao tác rất phổ biến và vì vậy ExpressJS cũng đã giúp chúng ta đơn giản hóa mọi thao tác xử lý chi tiết. Chúng ta đã không cần phải nhờ File System truy xuất tới tệp cần gửi trả để đọc nội dung, và cũng không cần phải thiết lập những chi tiết liên quan tới tiêu đề phản hồi như kiểu nội dung phản hồi là gì hay tín hiệu phản hồi 200 hay 404. 😄

Nếu như jQuery ở phía client-side là một nhà thông thái trong nhóm tác vụ làm việc với cấu trúc văn bản HTML và CSS; Thì ExpressJS ở đây lại đặc biệt am hiểu về những thao tác điều hướng route, và phản rồi response khi làm việc với các yêu cầu request gửi tới từ đâu đó.

Ở đây chúng ta đã sử dụng path ở lần gắn hàm xử lý sự kiện thứ hai là *, nó có nghĩa là hàm xử lý truyền vào ở đây sẽ được áp dụng cho tất cả các yêu cầu gửi tới. Ký hiệu này được sử dụng với ý nghĩa tương tự ở rất nhiều công cụ lập trình khác mà chúng ta đã học; Ví dụ như bộ chọn * của CSS cũng là để chọn tất cả các phần tử HTML có mặt trong trang web đơn; Hoặc trong các biểu thức thường thị RexExp giúp làm việc với các chuỗi, thì * cũng có ý nghĩa là bất kỳ kí tự nào. Vậy chúng ta cứ ghi nhớ * có nghĩa là bất kỳ cái gì cũng phù hợp. 😄

Làm quen với tài liệu của ExpressJS

Sau khi chúng ta đã hiểu sơ lược về những giá trị mà ExpressJS đem lại, việc tiếp tục tìm hiểu về framework này chắc chắn vẫn sẽ là xuất phát từ tài liệu chính thức trên trang chủ của frameworkExpressJS.com.

Bộ tài liệu chính thức mà ExpressJS cung cấp cho chúng ta rất gọn gàng với 5 chỉ mục chính ở phía bên trái được đặt trong một danh sách đóng/mở dạng accordion giúp chúng ta luôn luôn duy trì được cái nhìn tổng quan về các công cụ được cung cấp. Và điểm khởi đầu của framework là hàm express().

var express = require('express')
var app = express()

ExpressJS gọi phần mềm server của chúng ta là app (application) – hay ứng dụng – để biểu thị một phần mềm hoạt động qua tương tác mạng network nói chung. Và như vậy chúng ta có chỉ mục tiếp theo cần mở xem là Application.

var express = require('express')
var app = express()

app.get('/', function(req, res) {
  res.send('hello world')
})

app.listen(3000)

Bên cạnh đó thì object express cũng có một phương thức nổi bật so với số còn lại đó là express.Router() và chúng ta cũng thấy có một chỉ mục tương ứng cùng tên Router – tạm dịch là trình định tuyến – điều hướng yêu cầu nhận được tới đâu đó để xử lý. Các router sẽ giúp chúng ta tách rời tác vụ phân tích và chuyển hướng yêu cầu khỏi phần thân chương trình chính ở tệp khởi tạo ứng dụng app trong trường hợp bạn có dự định xây dựng một thứ gì đó đồ sộ. 😄

var express =require('express')var router = express.Router()

router.get('/',function(req, res){
   res.send('hello world')})

module.exports ={ router }
var express =require('express')var app =express()var{ router }=require('./router.js')
app.use(router)

app.listen(3000)

Hai chỉ mục còn lại là RequestResponse thì chúng ta cũng có thể đoán ra được là liên quan tới 2 tham số đầu tiên (req, res) mà các hàm xử lý nhận được. Như vậy là chúng ta có thể thấy tổng quan những công cụ của ExpressJS được liệt kê trong trong tài liệu này sẽ giúp chúng ta đơn giản hóa các tác vụ phân tích và điều hướng yêu cầu tới những chu trình xử lý riêng. Như vậy thì chúng ta sẽ có thể tập trung tốt hơn vào việc viết code xử lý yêu cầu cụ thể và không tốn quá nhiều năng lượng vào thao tác phân tích địa chỉ yêu cầu và khởi tạo logic điều hướng.

Thế cái tác vụ tự động tạo ra mấy trang web đơn từ nguồn dữ liệu đơn giản sẽ được hỗ trợ ở chỗ nào?

À.. mình quên khuấy mất. Cái này mới là cái quan trọng nhất đối với nhu cầu tạo blog đơn giản của chúng ta hiện tại; Chứ cái tác vụ phân tích với điều hướng yêu cầu thì cũng chưa hẳn là quan trọng lắm. 😄

Phương thức app.render(view, callback) sẽ giúp chúng ta sử dụng các biểu mẫu template mô tả code HTML ở dạng chưa có dữ liệu thực tế – gắn với dữ liệu truy vấn được bởi logic cung cấp trong hàm callback và tạo ra code HTML hoàn chỉnh để gửi trả cho trình duyệt web. Và như vậy là chúng ta sẽ cần tìm hiểu cách thức để tạo ra cái template mà chúng ta vừa nói đến, và… hoàn thiện trang blog đơn giản mà chúng ta đang xây dựng thôi. 😄

Tuy nhiên thì trước hết chúng ta vẫn nên có một lượt giới thiệu tổng quan về từng chỉ mục chính trong tài liệu của ExpressJS. Cũng giống như khi chúng ta học cách sử dụng Bootstrap hay jQuery ở phía mặt tiền front-end thôi; Chúng ta cần xem qua hết một lượt để nhớ mặt được kha khá những công cụ mà ExpressJS cung cấp, rồi sau đó mới có thể tự tin mà lần mò viết code được. 😄

Vậy, hẹn gặp lại bạn trong bài viết tiếp theo với chủ đề tìm hiểu về thao tác điều hướng yêu cầu trong ExpressJS. 😄

(Sắp đăng tải) [ExpressJS] Bài 2 – Phân tích yêu cầu và điều hướng cơ bản

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ