Next.js: Fullstack dalam Satu Proyek · 9/9
Proxy: kode yang jalan sebelum setiap route
Redirect, routing bahasa, dan gerbang autentikasi — file yang dulu bernama middleware.
Baca 22 menit
Setelah pelajaran ini kamu bisa
- Menulis proxy yang jalan sebelum setiap route yang cocok
- Menulis matcher yang mengecualikan aset
- Menjelaskan apa yang tidak boleh diimpor kode proxy
- Menjelaskan kenapa pemeriksaan auth tidak boleh hanya ada di proxy
proxy.ts jalan di server sebelum sebuah route di-render. Ia bisa melakukan redirect, rewrite, atau menambah header berdasarkan request yang masuk.
// proxy.ts, at the project root - this is this project's real file
import { NextResponse, type NextRequest } from "next/server";
import { LOCALE_COOKIE, isLocale, negotiateLocale } from "@/features/i18n/locales";
export function proxy(request: NextRequest) {
const { pathname } = request.nextUrl;
// Already has a locale? Nothing to do.
if (isLocale(pathname.split("/")[1])) return;
// An explicit choice beats the browser's Accept-Language header.
const chosen = request.cookies.get(LOCALE_COOKIE)?.value;
const locale = isLocale(chosen)
? chosen
: negotiateLocale(request.headers.get("accept-language"));
request.nextUrl.pathname = "/" + locale + (pathname === "/" ? "" : pathname);
return NextResponse.redirect(request.nextUrl);
}
export const config = {
matcher: ["/((?!_next|api|.*\\.).*)"],
};Matcher
Tanpa matcher, proxy-nya jalan di setiap request — termasuk bundle _next/static, gambar, dan favicon. Itu lambat sekaligus sumber bug yang sangat membingungkan, karena CSS-mu mulai ikut ter-redirect.
Matcher sebenarnya dari proyek ini, diuji terhadap request yang dibuat saat halaman dimuat.
Hasil
Tekan Jalankan untuk melihat hasilnya.
Ini jalan di browser kamu, di dalam sandbox. Apa pun yang kamu tulis di sini tidak bisa merusak situs.
Apa yang tidak boleh dilakukan kode proxy
Kode proxy bisa jalan di edge runtime, dan dokumentasinya menyatakan jelas bahwa ia tidak boleh mengandalkan module bersama atau global. Itu batasan nyata dengan konsekuensi praktis.
- Tanpa module `node:`. Tidak ada
fs, tidak adacrypto, tidak adanode:sqlite. - Tanpa akses database. Bisa jadi tidak ada koneksi yang tersedia di tempat ini berjalan.
- Jangan yang berat. Ia jalan sebelum setiap request yang cocok, jadi biayanya dibayar di setiap kali halaman dimuat.
- Hanya import yang pure. Proxy proyek ini mengimpor satu module bebas dependency berisi function murni, dengan sengaja.
Auth di proxy: perlu, tapi tidak cukup
Proxy adalah tempat yang bagus untuk mengalihkan pengunjung yang belum masuk dari /dashboard. Ia bukan tempat untuk membuat satu-satunya keputusan authorization-mu.
// A reasonable optimisation: skip rendering a page they cannot see.
export function proxy(request: NextRequest) {
const hasCookie = Boolean(request.cookies.get("session")?.value);
if (!hasCookie && request.nextUrl.pathname.includes("/dashboard")) {
return NextResponse.redirect(new URL("/en/sign-in", request.url));
}
}
// But the cookie only proves one EXISTS - not that it is valid, unexpired,
// or belongs to someone allowed here. So the page checks properly anyway:
export default async function DashboardPage() {
const user = await getSessionUser(); // verifies against the database
if (!user) redirect("/en/sign-in");
if (user.role !== "lead") notFound(); // authorisation, server-side
}Tugas praktik
Di proyek ini, ubah sementara matcher di proxy.ts jadi ["/(.*)"], restart dev, lalu buka halaman mana pun. Halamannya akan tampak rusak dan tanpa style — buka tab Network dan kamu akan melihat request CSS dan JS-nya ikut di-redirect. Lalu kembalikan matcher aslinya. Kamu baru saja melihat kenapa negative lookahead itu ada.
Hasil yang diharapkan
Halaman tanpa style, dan redirect pada request aset di tab Network.