Create a Middleware in NextJS 13

Nay mình sẽ thực hiện một chức năng quan trọng trong Next.js. Đó là chúng ta cần xử lý Middleware , vậy middleware để làm gì? Chúng ta có thể hiểu như sau:

Middleware là có tác dụng xử lý các vấn đề, khi một yêu cầu nào đó cần chạy vào phần mềm của ta, thì cần phải đi qua thằng Middleware này trước tiên. Đi qua nó trước để làm gì? à đi qua nó để kiểm tra xem các thông tin người dùng có hợp lệ hay không, kiểm tra như: origin cookie, pathname, hostnameheader, ..... mà ta cho phép truy cập vào các router trong ứng dụng. Tùy vào ứng dụng mà ta cài đặt kiểm tra nhé

Nếu các bạn đã làm qua về Middleware trong Laravel, hay React, thì các bạn có thể hình dung được, nó cũng giống như vậy

VD :

Laravel : thì ta cần tạo Middleware để check Authentication của người dùng hoặc kiểm tra Role , Group, Permissions,...

React : ta thường dùng middleware trong các thư viện Redux, Redux-Toolkit, Redux-Saga,...

NextJS : mình tạo một file Middleware nằm cùng cấp với app , pages, hoặc bên trong src,  Nó sẽ kiểm tra mọi tuyến đường đi qua ứng dụng

Okay, đầu tiền mình sẽ tạo một file middleware.ts cùng cấp với thư mục app

import { NextRequest, NextResponse } from "next/server";
const allow_origin_lists :string[]   = process.env.NODE_ENV==='production'?['https://hoanguyenit.com','https://100daysofcode.hoanguyenit.com']:
['https://www.google.com','http://localhost:3000']
export default function middleware(request: NextRequest){
    console.log("env",process.env.NODE_ENV);
    console.log("Host",request.headers.get('host'))
    console.log("Origin",request.headers.get('origin'));
    console.log("Url",request.url)
    console.log("Mehod:",request.method);

    //Chúng ta kiểm tra các request tại đây
    const origin: string | null  = request.headers.get('origin')
    const res = NextResponse.next()
    const res_404 = new NextResponse(null,
        {
            status: 404,
            statusText:"Bad request",
            headers:{
                'Content-Type':'text/plain'
            }
        })
    
    console.log(allow_origin_lists);
    if(origin && !allow_origin_lists.includes(origin)){
        return res_404;
    }

    // add the CORS headers to the response
    res.headers.append('Access-Control-Allow-Credentials', "true")
    res.headers.append('Access-Control-Allow-Origin', origin) 
    res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT')
    res.headers.append(
        'Access-Control-Allow-Headers',
        'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
    )

    return res;
}
export const config = {
    matcher:[ '/api/:path*']
  }

Bạn nhìn đoạn code trên mình có dùng check các origin cho phép truy cập vào ứng dụng

const allow_origin_lists :string[]   = process.env.NODE_ENV==='production'?['https://100daysofcode.hoanguyenit.com']:
['https://www.google.com','http://localhost:3000']

Bên cạnh đó trong function middleware ta có thể kiểm tra các giá trị tham số như, method, origin, url, host. Các giá trị này rất cần thiết khi ta xác thực các yêu cầu người dùng đến từ đâu, website nào, phương thức cho phép

 console.log("env",process.env.NODE_ENV);
    console.log("Host",request.headers.get('host'))
    console.log("Origin",request.headers.get('origin'));
    console.log("Url",request.url)
    console.log("Mehod:",request.method);

Tiếp theo ta có thể kiểm tra origin có nằm trong array origin mà ta cho phép hay không. Không có thì response về 404

 const res_404 = new NextResponse(null,
        {
            status: 404,
            statusText:"Bad request",
            headers:{
                'Content-Type':'text/plain'
            }
        })
    
if(origin && !allow_origin_lists.includes(origin)){
        return res_404;
    }

Còn đoạn dưới đây thì cũng dễ hình dùng được: 

Access-Control-Allow-Credentials : phép trình duyệt gửi yêu cầu CORS với thông tin xác thực (như cookie hoặc một thông tin xác thực khác)

Access-Control-Allow-Origin : xác định nguồn gốc mà trình duyệt được phép gửi yêu cầu CORS đến

Access-Control-Allow-Methods : xác định các phương thức HTTP mà máy chủ chấp nhận từ các trình duyệt gửi yêu cầu CORS

Access-Control-Allow-Headers : xác định các tiêu đề HTTP tùy chọn mà trình duyệt có thể bao gồm trong yêu cầu CORS. Điều này quan trọng nếu bạn muốn cho phép trình duyệt gửi các tiêu đề tùy chỉnh khác. Trong trường hợp này, danh sách các tiêu đề được liệt kê, bao gồm X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version

res.headers.append('Access-Control-Allow-Credentials', "true")
    res.headers.append('Access-Control-Allow-Origin', origin) 
    res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT')
    res.headers.append(
        'Access-Control-Allow-Headers',
        'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
    )

Tiếp đây ta có thể cung cấp một số route cho Middleware biết check các route quan trọng của ta, ta có thể custom nó, tùy ý

export const config = {
    matcher:[ '/api/:path*']
  }

Cái config matcher bên trên, nếu bạn không cũng cấp cho Middleware thì nó mặt định sẽ quét route toàn bộ ứng dụng bạn có thể xem hình tại đây

Còn nếu bạn cung cấp cho Middleware biết cần kiểm tra các tuyến đường route nào, thì nó chỉ kiểm tra trong các tuyến đường route đó mà thôi

VD: tôi chỉ cung cấp cho middleware check trong route /api/:path* . Thì nó chỉ check tại đường dẫn đó thôi

Okay, giờ ta kiểm tra thử xem nhé

Ta nhìn thấy không bị báo cors, vậy là ok rồi

Ta thử trang khác xem

Bị báo lỗi Cors, vì ứng dụng của ta đang ở trạng thái phát triển(development) , chưa có (production)

Có rất là nhiều thứ để bạn có thể kiểm tra, chẳng hạn như, kiểm tra có phải đang dùng điện thoại hay không

import { NextResponse, userAgent } from 'next/server'
......
 const { device } = userAgent(request)
if (host=== 'hoanguyenit.com' && device.type === 'mobile') {
    const url = request.nextUrl.clone()
   //cập nhật lại host name
    url.hostname = 'm.hoanguyenit.com'
  // chuyển hướng nó
    return NextResponse.redirect(url)
  }

Hoặc ví dụ kiểm tra đường dẫn pathname "/api/post/12" đổi thành /api/post/99

if (request.nextUrl.pathname === 'api/post/12')
    const url = request.nextUrl.clone()
    url.pathname = '/api/post/99'
    return NextResponse.redirect(url)
  }

 

Bài Viết Liên Quan

Messsage

Ủng hộ tôi bằng cách click vào quảng cáo. Để tôi có kinh phí tiếp tục phát triển Website!(Support me by clicking on the ad. Let me have the money to continue developing the Website!)