乐闻世界logo
搜索文章和话题

How does Astro's Middleware work? What are some common use cases for it?

2月21日 16:15

Astro's Middleware is a powerful feature that allows you to intercept and handle requests before they reach pages, enabling authentication, redirects, response modification, and more.

Core Concepts:

Middleware runs on the server side, can access the request object, and executes custom logic in the request processing chain.

Creating Middleware:

typescript
// src/middleware.ts import { defineMiddleware } from 'astro:middleware'; import type { MiddlewareResponseHandler } from 'astro'; export const onRequest: MiddlewareResponseHandler = async (context, next) => { // Handle request here // Call next() to continue the processing chain const response = await next(); // Can modify response response.headers.set('X-Custom-Header', 'Custom Value'); return response; };

Middleware Context:

typescript
// src/middleware.ts export const onRequest = async (context, next) => { // context contains the following properties: console.log(context.request); // Request object console.log(context.url); // URL object console.log(context.cookies); // Cookies console.log(context.locals); // Local data storage console.log(context.site); // Site configuration const response = await next(); return response; };

Use Cases:

  1. Authentication and Authorization:
typescript
// src/middleware.ts export const onRequest = async (context, next) => { const protectedRoutes = ['/dashboard', '/settings', '/profile']; const currentPath = context.url.pathname; if (protectedRoutes.some(route => currentPath.startsWith(route))) { const token = context.cookies.get('auth-token'); if (!token) { return context.redirect('/login'); } // Verify token const user = await verifyToken(token.value); if (!user) { return context.redirect('/login'); } // Store user info in locals context.locals.user = user; } return next(); };
  1. Redirect Management:
typescript
// src/middleware.ts export const onRequest = async (context, next) => { const redirects = { '/old-url': '/new-url', '/old-page': '/new-page', }; const currentPath = context.url.pathname; if (redirects[currentPath]) { return context.redirect(redirects[currentPath], 301); } return next(); };
  1. Internationalization (i18n):
typescript
// src/middleware.ts export const onRequest = async (context, next) => { const supportedLocales = ['en', 'zh', 'ja']; const defaultLocale = 'en'; // Get language from URL const pathSegments = context.url.pathname.split('/'); const locale = pathSegments[1]; // Check if it's a supported language if (supportedLocales.includes(locale)) { context.locals.locale = locale; return next(); } // Get language from Accept-Language header const acceptLanguage = context.request.headers.get('accept-language'); const browserLocale = acceptLanguage?.split(',')[0].split('-')[0] || defaultLocale; const targetLocale = supportedLocales.includes(browserLocale) ? browserLocale : defaultLocale; return context.redirect(`/${targetLocale}${context.url.pathname}`); };
  1. Logging:
typescript
// src/middleware.ts export const onRequest = async (context, next) => { const startTime = Date.now(); const response = await next(); const duration = Date.now() - startTime; console.log(`${context.request.method} ${context.url.pathname} - ${duration}ms`); return response; };
  1. CORS Handling:
typescript
// src/middleware.ts export const onRequest = async (context, next) => { const response = await next(); response.headers.set('Access-Control-Allow-Origin', '*'); response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization'); return response; };

Conditional Middleware:

typescript
// src/middleware.ts export const onRequest = async (context, next) => { // Only apply middleware to specific paths if (context.url.pathname.startsWith('/api/')) { console.log('API request:', context.url.pathname); } return next(); };

Middleware Priority:

Astro supports defining middleware at different levels:

  1. Global Middleware: src/middleware.ts - Applied to all requests
  2. Route Middleware: Defined in specific route directories - Applied to that route and its sub-routes
typescript
// src/middleware.ts (global) export const onRequest = async (context, next) => { console.log('Global middleware'); return next(); };
typescript
// src/pages/dashboard/middleware.ts (route-specific) export const onRequest = async (context, next) => { console.log('Dashboard middleware'); return next(); };

Using locals to Pass Data:

typescript
// src/middleware.ts export const onRequest = async (context, next) => { // Set data in middleware context.locals.user = await getUser(context); context.locals.theme = 'dark'; const response = await next(); return response; };
astro
--- // Use locals in pages const user = Astro.locals.user; const theme = Astro.locals.theme; --- <h1>Welcome, {user?.name}</h1> <p>Current theme: {theme}</p>

Error Handling:

typescript
// src/middleware.ts export const onRequest = async (context, next) => { try { return await next(); } catch (error) { console.error('Middleware error:', error); return new Response('Internal Server Error', { status: 500, headers: { 'Content-Type': 'text/plain' }, }); } };

Performance Optimization:

typescript
// src/middleware.ts export const onRequest = async (context, next) => { // Cache frequently accessed data const cacheKey = `user:${context.cookies.get('user-id')?.value}`; const cachedUser = await cache.get(cacheKey); if (cachedUser) { context.locals.user = cachedUser; return next(); } const user = await fetchUser(context.cookies.get('user-id')?.value); await cache.set(cacheKey, user, { ttl: 3600 }); context.locals.user = user; return next(); };

Best Practices:

  1. Keep middleware concise and efficient
  2. Avoid time-consuming operations in middleware
  3. Use caching to optimize performance
  4. Use locals appropriately to pass data
  5. Implement proper error handling
  6. Consider middleware execution order
  7. Only use redirects when necessary

Astro's middleware provides powerful request processing capabilities for building complex applications, especially suitable for projects requiring authentication, authorization, internationalization, and other features.

标签:Astro