ข้ามไปยังเนื้อหา

Middleware และ Tower

ใน Express middleware คือ function (req, res, next) => void ที่คุณลงทะเบียนด้วย app.use() ใน Axum middleware คือ Tower layer — เป็น wrapper แบบ composable รอบ Service แนวคิดเหมือนกัน (intercept → process → forward) แต่ Tower เป็น protocol-agnostic และทำงานที่ compile time

TypeScript
// Express — register middleware globally
import express from 'express';
import cors from 'cors';
import morgan from 'morgan';
const app = express();
app.use(cors({ origin: 'https://myapp.com' }));
app.use(morgan('combined'));
app.use(express.json());
app.get('/users', listUsers);
Rust
use axum::{routing::get, Router};
use tower_http::{cors::CorsLayer, trace::TraceLayer};
use tower::ServiceBuilder;
use http::HeaderValue;
let app = Router::new()
.route("/users", get(list_users))
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(
CorsLayer::new()
.allow_origin("https://myapp.com".parse::<HeaderValue>().unwrap())
.allow_methods([http::Method::GET, http::Method::POST])
)
);

tower-http มี CorsLayer ที่ใช้งานได้เหมือน cors npm package เพิ่มใน Cargo.toml ด้วย tower-http = { version = "0.5", features = ["cors"] }

use tower_http::cors::{Any, CorsLayer};
use axum::http::Method;
let cors = CorsLayer::new()
.allow_origin(Any) // any origin (dev only)
.allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE])
.allow_headers(Any);
let app = Router::new()
.route("/users", get(list_users))
.layer(cors);

TraceLayer ของ tower-http รวมกับ tracing เพื่อ log ทุก request/response เพิ่ม tower-http = { version = "0.5", features = ["trace"] } ใน Cargo.toml

use tower_http::trace::TraceLayer;
let app = Router::new()
.route("/users", get(list_users))
.layer(TraceLayer::new_for_http());

เริ่ม app ด้วย RUST_LOG=tower_http=debug cargo run เพื่อดู structured request logs

Tower layer จะ wrap service ที่อยู่ชั้นล่างถัดไป คุณแนบ layer กับทั้ง router หรือเจาะจงเฉพาะ route group ก็ได้:

TypeScript
// Express — scoped middleware
import authMiddleware from './auth';
const protectedRouter = express.Router();
protectedRouter.use(authMiddleware);
protectedRouter.get('/profile', getProfile);
app.use('/api', protectedRouter);
Rust
use axum::Router;
use tower_http::auth::RequireAuthorizationLayer;
// Layer applied only to the protected sub-router
let protected_routes = Router::new()
.route("/profile", get(get_profile))
.layer(RequireAuthorizationLayer::bearer("secret-token"));
let app = Router::new()
.route("/health", get(health))
.nest("/api", protected_routes);

รันบนเครื่องของคุณ — middleware ต้องการ Axum server ที่กำลังทำงาน รันด้วย RUST_LOG=tower_http=debug cargo run

สิ่งเทียบเท่า `app.use(cors())` ของ Axum/Tower คืออะไร?
crate ใดที่ให้ `CorsLayer` และ `TraceLayer`?
คุณ apply Tower layer กับเฉพาะกลุ่ม routes อย่างไร?