Bahasa Indonesia

Jelajahi middleware Next.js, fitur canggih untuk mencegat permintaan. Pelajari cara menerapkan autentikasi, otorisasi, pengalihan, dan pengujian A/B.

Middleware Next.js: Menguasai Intersepsi Permintaan untuk Aplikasi Dinamis

Middleware Next.js menyediakan cara yang fleksibel dan canggih untuk mencegat dan memodifikasi permintaan masuk sebelum mencapai rute Anda. Kemampuan ini memungkinkan Anda untuk mengimplementasikan berbagai fitur, mulai dari autentikasi dan otorisasi hingga pengalihan dan pengujian A/B, sambil mengoptimalkan performa. Panduan komprehensif ini akan memandu Anda melalui konsep inti middleware Next.js dan menunjukkan cara memanfaatkannya secara efektif.

Apa itu Middleware Next.js?

Middleware di Next.js adalah sebuah fungsi yang berjalan sebelum sebuah permintaan diselesaikan. Ini memungkinkan Anda untuk:

Fungsi middleware didefinisikan dalam file middleware.ts (atau middleware.js) di root proyek Anda. Fungsi ini dieksekusi untuk setiap rute dalam aplikasi Anda, atau untuk rute tertentu berdasarkan matcher yang dapat dikonfigurasi.

Konsep Utama dan Manfaat

Objek Request

Objek request menyediakan akses ke informasi tentang permintaan yang masuk, termasuk:

Objek Response

Fungsi middleware mengembalikan objek Response untuk mengontrol hasil dari permintaan. Anda dapat menggunakan respons berikut:

Matcher

Matcher memungkinkan Anda untuk menentukan rute mana yang harus diterapkan middleware Anda. Anda dapat mendefinisikan matcher menggunakan ekspresi reguler atau pola path. Ini memastikan bahwa middleware Anda hanya berjalan saat diperlukan, meningkatkan performa dan mengurangi overhead.

Edge Runtime

Middleware Next.js berjalan di Edge Runtime, yang merupakan lingkungan runtime JavaScript ringan yang dapat di-deploy dekat dengan pengguna Anda. Kedekatan ini meminimalkan latensi dan meningkatkan performa keseluruhan aplikasi Anda, terutama untuk pengguna yang terdistribusi secara global. Edge Runtime tersedia di Edge Network Vercel dan platform lain yang kompatibel. Edge Runtime memiliki beberapa batasan, khususnya penggunaan API Node.js.

Contoh Praktis: Menerapkan Fitur Middleware

1. Autentikasi

Middleware autentikasi dapat digunakan untuk melindungi rute yang mengharuskan pengguna untuk login. Berikut adalah contoh cara menerapkan autentikasi menggunakan cookie:


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 return NextResponse.next()
}

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

Middleware ini memeriksa keberadaan cookie auth_token. Jika cookie tidak ditemukan, pengguna dialihkan ke halaman /login. config.matcher menetapkan bahwa middleware ini hanya boleh berjalan untuk rute di bawah /dashboard.

Perspektif Global: Sesuaikan logika autentikasi untuk mendukung berbagai metode autentikasi (mis., OAuth, JWT) dan berintegrasi dengan penyedia identitas yang berbeda (mis., Google, Facebook, Azure AD) untuk melayani pengguna dari berbagai wilayah.

2. Otorisasi

Middleware otorisasi dapat digunakan untuk mengontrol akses ke sumber daya berdasarkan peran atau izin pengguna. Misalnya, Anda mungkin memiliki dasbor admin yang hanya dapat diakses oleh pengguna tertentu.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 const token = request.cookies.get('auth_token');

 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 // Contoh: Ambil peran pengguna dari API (ganti dengan logika Anda yang sebenarnya)
 const userResponse = await fetch('https://api.example.com/userinfo', {
 headers: {
 Authorization: `Bearer ${token}`,
 },
 });
 const userData = await userResponse.json();

 if (userData.role !== 'admin') {
 return NextResponse.redirect(new URL('/unauthorized', request.url))
 }

 return NextResponse.next()
}

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

Middleware ini mengambil peran pengguna dan memeriksa apakah mereka memiliki peran admin. Jika tidak, mereka dialihkan ke halaman /unauthorized. Contoh ini menggunakan endpoint API placeholder. Ganti `https://api.example.com/userinfo` dengan endpoint server autentikasi Anda yang sebenarnya.

Perspektif Global: Perhatikan peraturan privasi data (mis., GDPR, CCPA) saat menangani data pengguna. Terapkan langkah-langkah keamanan yang sesuai untuk melindungi informasi sensitif dan memastikan kepatuhan terhadap hukum setempat.

3. Pengalihan

Middleware pengalihan dapat digunakan untuk mengalihkan pengguna berdasarkan lokasi, bahasa, atau kriteria lainnya. Misalnya, Anda mungkin mengalihkan pengguna ke versi situs web Anda yang dilokalkan berdasarkan alamat IP mereka.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const country = request.geo?.country || 'US'; // Default ke US jika geo-lokasi gagal

 if (country === 'DE') {
 return NextResponse.redirect(new URL('/de', request.url))
 }

 if (country === 'FR') {
 return NextResponse.redirect(new URL('/fr', request.url))
 }

 return NextResponse.next()
}

export const config = {
 matcher: ['/'],
}

Middleware ini memeriksa negara pengguna berdasarkan alamat IP mereka dan mengalihkan mereka ke versi situs web yang dilokalkan yang sesuai (/de untuk Jerman, /fr untuk Prancis). Jika geo-lokasi gagal, middleware ini akan menggunakan versi AS sebagai default. Perhatikan bahwa ini bergantung pada properti geo yang tersedia (mis., saat di-deploy di Vercel).

Perspektif Global: Pastikan situs web Anda mendukung beberapa bahasa dan mata uang. Berikan pengguna pilihan untuk memilih bahasa atau wilayah pilihan mereka secara manual. Gunakan format tanggal dan waktu yang sesuai untuk setiap lokal.

4. Pengujian A/B

Middleware dapat digunakan untuk mengimplementasikan pengujian A/B dengan secara acak menugaskan pengguna ke varian halaman yang berbeda dan melacak perilaku mereka. Berikut adalah contoh yang disederhanakan:


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

function getRandomVariant() {
 return Math.random() < 0.5 ? 'A' : 'B';
}

export function middleware(request: NextRequest) {
 let variant = request.cookies.get('variant')?.value;

 if (!variant) {
 variant = getRandomVariant();
 const response = NextResponse.next();
 response.cookies.set('variant', variant);
 return response;
 }

 if (variant === 'B') {
 return NextResponse.rewrite(new URL('/variant-b', request.url));
 }

 return NextResponse.next();
}

export const config = {
 matcher: ['/'],
}

Middleware ini menugaskan pengguna ke varian 'A' atau 'B'. Jika pengguna belum memiliki cookie variant, cookie akan ditetapkan dan diatur secara acak. Pengguna yang ditugaskan ke varian 'B' akan ditulis ulang ke halaman /variant-b. Anda kemudian akan melacak kinerja setiap varian untuk menentukan mana yang lebih efektif.

Perspektif Global: Pertimbangkan perbedaan budaya saat merancang pengujian A/B. Apa yang berhasil di satu wilayah mungkin tidak sesuai dengan pengguna di wilayah lain. Pastikan platform pengujian A/B Anda mematuhi peraturan privasi di berbagai wilayah.

5. Feature Flags

Feature flags memungkinkan Anda untuk mengaktifkan atau menonaktifkan fitur di aplikasi Anda tanpa men-deploy kode baru. Middleware dapat digunakan untuk menentukan apakah pengguna harus memiliki akses ke fitur tertentu berdasarkan ID pengguna, lokasi, atau kriteria lainnya.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 // Contoh: Ambil feature flag dari API
 const featureFlagsResponse = await fetch('https://api.example.com/featureflags', {
 headers: {
 'X-User-Id': 'user123',
 },
 });
 const featureFlags = await featureFlagsResponse.json();

 if (featureFlags.new_feature_enabled) {
 // Aktifkan fitur baru
 return NextResponse.next();
 } else {
 // Nonaktifkan fitur baru (mis., alihkan ke halaman alternatif)
 return NextResponse.redirect(new URL('/alternative-page', request.url));
 }
}

export const config = {
 matcher: ['/new-feature'],
}

Middleware ini mengambil feature flag dari API dan memeriksa apakah flag new_feature_enabled telah diatur. Jika ya, pengguna dapat mengakses halaman /new-feature. Jika tidak, mereka dialihkan ke /alternative-page.

Perspektif Global: Gunakan feature flags untuk meluncurkan fitur baru secara bertahap kepada pengguna di berbagai wilayah. Ini memungkinkan Anda untuk memantau performa dan mengatasi masalah apa pun sebelum merilis fitur ke audiens yang lebih luas. Juga, pastikan sistem feature flagging Anda dapat diskalakan secara global dan memberikan hasil yang konsisten terlepas dari lokasi pengguna. Pertimbangkan batasan peraturan regional untuk peluncuran fitur.

Teknik Lanjutan

Merangkai Middleware

Anda dapat merangkai beberapa fungsi middleware menjadi satu untuk melakukan serangkaian operasi pada sebuah permintaan. Ini bisa berguna untuk memecah logika yang kompleks menjadi modul-modul yang lebih kecil dan lebih mudah dikelola.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
 const response = NextResponse.next();

 // Fungsi middleware pertama
 const token = request.cookies.get('auth_token');
 if (!token) {
 return NextResponse.redirect(new URL('/login', request.url))
 }

 // Fungsi middleware kedua
 response.headers.set('x-middleware-custom', 'value');

 return response;
}

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

Contoh ini menunjukkan dua middleware dalam satu. Yang pertama melakukan autentikasi dan yang kedua mengatur header kustom.

Menggunakan Variabel Lingkungan

Simpan informasi sensitif, seperti kunci API dan kredensial database, di dalam variabel lingkungan daripada menuliskannya secara langsung dalam fungsi middleware Anda. Ini meningkatkan keamanan dan memudahkan pengelolaan konfigurasi aplikasi Anda.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const API_KEY = process.env.API_KEY;

export async function middleware(request: NextRequest) {
 const response = await fetch('https://api.example.com/data', {
 headers: {
 'X-API-Key': API_KEY,
 },
 });

 // ...
}

export const config = {
 matcher: ['/data'],
}

Dalam contoh ini, API_KEY diambil dari variabel lingkungan.

Penanganan Eror

Terapkan penanganan eror yang kuat dalam fungsi middleware Anda untuk mencegah eror tak terduga yang dapat merusak aplikasi Anda. Gunakan blok try...catch untuk menangkap eksepsi dan mencatat eror dengan tepat.


// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
 try {
 const response = await fetch('https://api.example.com/data');
 // ...
 } catch (error) {
 console.error('Error fetching data:', error);
 return NextResponse.error(); // Atau alihkan ke halaman eror
 }
}

export const config = {
 matcher: ['/data'],
}

Praktik Terbaik

Pemecahan Masalah Umum

Kesimpulan

Middleware Next.js adalah alat yang canggih untuk membangun aplikasi web yang dinamis dan personal. Dengan menguasai intersepsi permintaan, Anda dapat mengimplementasikan berbagai fitur, mulai dari autentikasi dan otorisasi hingga pengalihan dan pengujian A/B. Dengan mengikuti praktik terbaik yang diuraikan dalam panduan ini, Anda dapat memanfaatkan middleware Next.js untuk menciptakan aplikasi yang berperforma tinggi, aman, dan dapat diskalakan yang memenuhi kebutuhan basis pengguna global Anda. Manfaatkan kekuatan middleware untuk membuka kemungkinan baru dalam proyek Next.js Anda dan memberikan pengalaman pengguna yang luar biasa.