Trước khi có middleware, để thực hiện được các xử lý như redirect nếu không có quyền truy cập, rewrite 1 đường dẫn ảnh tới 1 server bên ngoài, hay bổ sung thêm cookie vào headers đều phải làm thủ công

Cụ thể là chúng ta đều phải thực hiện những việc trên trong từng page, hoặc phải bổ sung config vào next.config.js. Bây giờ, với sự bổ sung _middleware.ts mọi việc sẽ dễ dàng hơn nhiều

Sử dụng

Đầu tiên, để sử dụng _middleware.ts chúng ta phải cài đặt phiên bản mới nhất của Nextjs. Dù bạn đạn chạy version cũ hơn của Next.js thì vẫn có thể chạy lệnh dưới đây để nâng cấp

$ yarn add next@latest 

Sau đó, tạo 1 file có tên là _middleware.ts trong thư mục /pages

// pages/_middleware.ts
import type { NextFetchEvent, NextRequest } from 'next/server'

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  return new Response('Hello, world!')
}

Lưu ý rằng:

Do bạn có thể sử dụng _middleware.ts ở bất kì đâu trong /pages nên hiển nhiên chúng ta cũng có thể sử dụng nó trong /pages/api/

Xong, thủ tục thì chỉ đơn giản như vậy thôi

Thứ tự thực thi

Nếu bạn tạo middleware.ts bên trong thư mục /pages như hình dưới, thì nó sẽ được thực thi trước toàn bộ routes. Do đó, /pages/_middleware.ts sẽ chạy trước, sau đó đến /pages/index.tsx, /pages/about.tsx, /pages/teams.tsx

- package.json
- /pages
    _middleware.ts # chạy trước toàn bộ routes 
    index.tsx
    about.tsx
    teams.tsx

Còn nếu bạn có nhiều cấp thư mục con, thì thứ tự thực thi sẽ là từ ngoài vào trong

- package.json
- /pages
    index.tsx
    _middleware.ts # chạy thứ 1
    - /about
      _middleware.ts # chạy thứ 2
      about.tsx
      - /teams 
        _middleware.ts # chạy thứ 3 => do nó nằm trong /about/teams
        teams.tsx

Giải thích nội dung bên trong middleware.ts

Nhìn đoạn code bên dưới, có 1 số Class chúng ta cần quan tâm: NextRequest, NextFetchEvent, Response, NextResponse. Tuy nhiên, NextRequest đã khá quen thuộc, nên bài viết này chỉ giải thích về các Class còn lại

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  return new Response("Hello, world!");
}

Vậy, ta có thể làm gì với những Class này ?

Đầu tiên, về Response - nó là chuẩn Web API Response

Chúng ta sử dụng Response để trả về kết quả, như ví dụ trên thì kết quả hiển thị trên trình duyệt sẽ là

next12-2.jpg
next12-2.jpg (Xem ảnh gốc)

Các bạn có thể đọc thêm tài liệu về Web API Response tại MDN, dưới đây là 1 số cách sử dụng cơ bản

1/ Redirecting

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  return Response.redirect("https://google.com");
}

2/ Trả về json object, thêm cookie vào header

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  const headers = new Headers();

  headers.append("Content-Type", "application/json");
  
  // bổ sung `name` và httpOnly
  headers.set("Set-Cookie", "name=12; HttpOnly"); 

  return new Response(JSON.stringify({ name: "John", age: 32 }), {
    status: 200,
    statusText: "OK",
    headers: headers,
  });
}

next12-3.jpg
next12-3.jpg (Xem ảnh gốc)

Class thứ 2 là NextResponse

Thực ra, NextResponse chỉ là 1 Class mở rộng của Response, nó cung cấp 1 số phương thức tiện dụng sau

  • cookie(name, value, options)
  • clearCookie(name)
  • redirect(url)
  • rewrite(url)
  • next()

Các phương thức trên tương đối dễ hiểu do đó me sẽ chỉ giải thích 2 phương thức là rewrite(url)next()

1/ rewrite(url)

Phương thức này được sử dụng chủ yếu để chuyển hướng 1 địa chỉ url tới 1 địa chỉ url khác. Tuy nhiên, khác với redirect, rewrite không làm thay đổi địa chỉ url trên thanh địa chỉ của trình duyệt. Chỉ có 1 điểm giống nhau giữa redirectrewrite đó là kết quả hiển thị

// redirect
http://blog/unknown-post 
=> redirect(/404) 
http://blog/404 

// rewrite
http://blog/unknown-post 
=> rewrite(/404)
http://blog/unknown-post

2/ next()

Phương thức này thì đơn giản hơn, nó nói cho server biết rằng, cứ tiếp tục xử lý request, không có vấn đề gì cả

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  return NextResponse.next();
}

Kết quả là

next12-5.jpg
next12-5.jpg (Xem ảnh gốc)

Còn nếu sử dụng Response

export function middleware(req: NextRequest, ev: NextFetchEvent) {
  return return new Response('Hello, world!');
}

Thì kết quả là

next12-2.jpg
next12-2.jpg (Xem ảnh gốc)

Cuối cùng, class thứ 3 NextFetchEvent

Updating ....