Skip to content
youhoc
  • Pages
    • Home
    • Modern App Guidelines
    • Linux
      • Day 1: Linux Distributions & Navigation
      • Day 2: User Management
      • Day 3: File Permission & Ownership
      • Day 4: Package Management
      • Day 5: Services Management
    • Javascript
      • JS The Weird Part
        • Execution Context
        • Types & Operators
        • Objects & Functions
        • Error Handling & Strict Mode
        • Typescript, ES6, Tra
      • Modern JS
        • JS in the Browser
        • Data Storage JSON
        • Modern JS
        • Advanced Objects & Methods
        • Webpack & Babel
        • Async
      • jQuery
        • In-depth Analysis of jQuery
      • React-ready JS
        • Arrow Function
        • Template Literals
        • Logical AND, OR, Ternary, Nullish Operators
        • Destructuring & Rest Operator
        • Array Method
        • Immutability and Spread Operator
        • Promises, Async/Await, Callback
    • PHP
      • gruntJS
      • composer
      • MySQL
    • Docker
      • Container Basics
      • Container Networking
      • Container Image
      • Container Volume & Persistent Data
      • Dockerfile
      • Docker Compose
      • Docker Registry
    • Node.js
      • Installing & Exploring
      • Loading Modules
      • npm - Get Command Input
      • Web Server
        • icon picker
          Express Web Server
      • Template Engine & MVC
      • File System & Input Arguments
      • 6. Deploy to Heroku & Github
      • Authentication
      • 7. Databases
      • 8. Rest API
      • Errors
    • ReactJS
      • React from Andrew
        • Summary from Next
        • 1. Basics
        • 2. React Components
        • 3. Webpack
        • 4. Styling with SCSS
        • 5. React Router
        • 6. React Hook
      • Modern React From The Beginning
        • Intro to JSX
        • Vite Build Tools
        • Basic Component Creation
        • Component State
        • Props & Component Composition
        • useState with Inputs & Form Submission
        • useEffect, useRef & Local Storage
        • Async / Await and Http Request in React
        • React Router: Declarative Mode
        • ContextAPI
        • React Router: Framework Mode
          • File-routing & HTML Layouts
          • Server-side Data Query
          • Links & Navigation
          • Loaders
    • Typescript
      • Type User vs UserProp
    • Payload CMS
Share
Explore

Express Web Server

Install Express

Install
Basic Setup
Starting the server, keep restarting everytimes codes changed with nodemon

Middleware

Middleware is the nature of express.
pass req object through middle with app.use
use next to continue to next middleware
you can’t change req, res, next
middleware app.use(’/path/’, (req, res, next) => {}) will apply for path start with /
Body Parser
Express add new req.body and res.redirect
In order to use req.body , we need to install bodyParser
this is used as a middleware for ALL request
also, we need to separate post or get request
app.get, app.post just like app.use , but for GET and POST
app.use(’/’) — will run on any path start with /
app.get(’/’) — will run only on path / (exact path)
rules:
app.use for all middleware
app.get OR app.post for routes & logic
So far
res.send (thay cho res.write and res.end )
res.redirect (thay cho res.setHeader and res.location )
req.body , and bodyParses
app.use, app.get, app.post
Summary of app.use('/') vs app.get('/') Confusion
app.use('/') or app.use():
If all above matches all routes starting with the specified path (e.g., / matches /, /random, /about, etc.)...
If no path is specified, it defaults to '/' and applies to all routes.
Typically used for middleware or catch-all handlers.
app.get('/'):
Matches only the exact path for GET requests (e.g., / matches only /).
Use this for specific routes like the homepage.
Why /random404 Reaches the Homepage:
app.use('/', ...) matches all routes starting with /, so /random is included.
To fix this, use app.get('/') for the homepage.
Correct Usage:
Use app.get('/') for the homepage to ensure it matches only /.
Use app.use for middleware or a 404 handler to catch all unmatched routes.

Router

Why using both app.use and router.use

In Express.js, app.use and router.use serve similar purposes but are used in different contexts. Here's the breakdown:
app.use
Context: Used at the application level.
Purpose: Mounts middleware or routes at the application level. It applies to all requests that match the specified path.
router.use
Context: Used at the router level (when using express.Router()).
Purpose: Mounts middleware or sub-routes on a specific router instance. It allows you to modularize your routes.

Why use express.Router()?

express.Router() is used to create modular, mountable route handlers. It helps organize your application by separating routes into smaller, manageable pieces. This is especially useful for large applications.
Benefits of express.Router():
Modularity: You can define routes in separate files and import them into your main app.
Reusability: You can reuse the same router in different parts of your app.
Readability: Keeps your code clean and organized.

Example of express.Router() in a modular app:

Key Difference
app.use is for the entire application, while router.use is for a specific router instance.
Use express.Router() to create modular route handlers for better organization and scalability.

Helper or Utils

Constructing a helper to define a root dir for res.sendFile(’page.html’)

Static Public Folder

Next hay Không Next

1. next() là gì và khi nào thì “đi tiếp”?

Trong Express, mỗi request sẽ đi qua một chuỗi middleware/route handler.
Mỗi “chặng” trong chuỗi đó là một function kiểu:
Nếu gọi next() → Express chuyển control sang middleware/route kế tiếp trong stack.
Nếu gửi response (như res.send(), res.json(), res.sendFile(), res.end()) và không gọi next() → request thường kết thúc tại đây, Express sẽ không tự đi tiếp nữa (trừ khi bạn cố ý gọi next() sau đó – thường là không nên).
Nếu không gửi response, cũng không gọi next() → request sẽ bị treo (timeout).
Nói ngắn gọn:
next() dùng khi bạn chưa muốn kết thúc request, mà chỉ làm một bước xử lý rồi chuyển tiếp cho thằng kế tiếp.

2. Vì sao bodyParser.urlencoded(...)express.static(...) không thấy

next() mà vẫn đi tiếp?

Thực ra là có next(), chỉ là nó nằm bên trong function mà những dòng đó trả về.
Ví dụ:
Hai cái này không phải middleware trực tiếp.
Chúng là factory function – gọi xong thì trả về một middleware dạng:
Bạn có thể tưởng tượng:
urlencodedMiddleware bên trong có next():
Nó parse body xong, gắn req.body = {...}
Rồi nó gọi next() để chuyển sang middleware/route tiếp theo.
Tương tự với:
staticMiddleware sẽ:
Nếu tìm được file tương ứng URL → nó gửi file luôn (dùng res.sendFile/stream) và không gọi next() nữa (kết thúc luôn request).
Nếu không tìm được file → nó gọi next() để cho request đi tiếp tới route khác.
Nên lý do bạn không thấy next() là vì:
next() ở bên trong middleware mà những hàm đó trả về, chứ không nằm ở chỗ bạn viết.

3. res.send()res.sendFile() có “tự động stop code” không?

Có 2 ý phải tách ra:

3.1. Về phía HTTP response

Khi bạn gọi:
hoặc
thì Express sẽ:
Set status code (nếu chưa set)
Set header (Content-Type, Content-Length, v.v.)
Gửi body xuống client
Gọi res.end() → response coi như đã kết thúc.
Sau đó:
Bạn không được gọi thêm res.send(), res.json(), res.redirect() nữa.
Nếu cố làm, sẽ bị lỗi: Error: Can't set headers after they are sent to the client.

3.2. Về phía JavaScript code trong handler

res.send() không phải là return. Nó không tự động dừng function của bạn.
Code phía sau vẫn chạy bình thường:
Muốn “stop code” trong handler tại chỗ res.send(), bạn nên return luôn:
Pattern thực tế hay dùng là:
route handler: thường return res.send(...) để:
vừa gửi response
vừa kết thúc luôn function
middleware:
Nếu chỉ chuẩn bị dữ liệu (log, parse, auth,…) → không gửi response, chỉ next().
Nếu quyết định từ chối hoặc trả về luôn (403, 401, 500, …) → return res.status(...).send(...) và không gọi next() nữa.

4. Tóm lại cho dễ nhớ

next():
Dùng trong middleware để cho request đi tiếp.
Nếu không send response, cũng không next() → request bị treo.
bodyParser.urlencoded(...) và express.static(...):
hàm trả về middleware.
Middleware bên trong có next(), nên request vẫn đi tiếp khi cần.
res.send() / res.sendFile():
Về HTTP: kết thúc response → không gửi gì thêm được nữa.
Về code: không tự kết thúc function → code phía sau vẫn chạy nếu bạn không return.

Sending Response

HTML

JSON (for RestAPI)

Response will be auto convert to JSON.stringlify()
You can use an array of objects

Serve an entire directory (website with JS, CSS)

Popular file structure
node_modules
public (for public assets)
img
css
html
src (for starting JS file)
templates (for handlebars files - just like views and includes)
partials (includes like headers, footer, navigation)
views (just like pages)

Path Management to link to different folders & files
Default var name:
We could use these default var to manage paths, but we need a more absolute way to manage path....
When we serve a public static folder, we don’t need according routes.
the idea of a public static folder is to serve static assets, static HTML
we need a solution to serve dynamic pages

Serve dynamic pages

Use template engine ‘handlebars’
Actually, we should use handlebar for express, which is here:
Install into local application

Set default template engine in express

To use template engine, we need to use:

route (app.get)
res.render
templates / partials / views folders
files has to be put in right folders
no need to declare file ext .hbs
Be careful because res.render use index.hbs, but express will show public/index.html if available

The hbs files are basically the same with html files, except for placeholders in this format:

Partials are just like includes (for menu, header...)

To use hbs template without partials, there is no need to require hbs.
BUT to use partials, you HAVE TO require hbs module.
When you change the handble bars partials, nodemon will not auto restart, so you have to extend its scope
To include partials in view files

Serve Error Pages

Handler page for “No page found”
Place this route at the end of the file, below all other routes
You can’s send response twice
to stop after the first response, use return





Dynamic Params

Query String

localhost:1234/weather?location=Hanoi
Use req.query

4. Integrate with back-end JS

File Structure

Back-end code in src
export JSON via HTTP end-point
Front-end code in public
parse JSON into DOM
app.js is the starting point (but in src, act as router as well)
Back-end code modules:
node-fetch
Front-end code modules:
core:
path
fetch (this fetch is only for client side, surprise!!!! not accessiable in Node.js)
npm:
hbs
express

Steps to Integration

Build back-end code
Use app.js and route to build HTTP endpoint
Return JSON via HTTP endpoint (query string or POST)
Build front-end templates
Get JSON and parse into DOM

Tham khảo node-fetch

hàm core fetch chỉ xài được ở browser client
hàm node-fetch giống y chang, xài được ở back-end

Bài viết Tham khảo



Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.