Middleware
เปรียบเทียบโมเดล middleware
หัวข้อที่มีชื่อว่า “เปรียบเทียบโมเดล middleware”Express middleware คือ (req, res, next) => void เรียก next() เพื่อส่งต่อ หรือเรียก res.json() เพื่อจบ request เลย ส่วน Echo ใช้แนวคิด pipeline เดียวกันแต่อาศัย error-return pattern และ closure ของ Go:
// Echo middleware signaturefunc(next echo.HandlerFunc) echo.HandlerFuncMiddleware คืน HandlerFunc ใหม่ที่ wrap next ไว้ เรียก next(c) เพื่อส่งต่อ หรือคืน error เพื่อยกเลิก
// Express middlewarefunction requestLogger(req, res, next) { console.log(req.method + " " + req.path); next();}app.use(requestLogger);// Echo middlewarefunc RequestLogger(next echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { fmt.Printf("%s %s\n", c.Request().Method, c.Request().URL.Path) return next(c) // pass control forward }}
e.Use(RequestLogger)Built-in middleware
หัวข้อที่มีชื่อว่า “Built-in middleware”Echo มี middleware พร้อมใช้งานใน production หลายตัวใน sub-package middleware
// Express with popular packagesimport morgan from 'morgan';import cors from 'cors';
app.use(morgan('combined'));app.use(cors({ origin: '*' }));// No built-in recover — need express-async-errors or similar// Echo built-ins — no extra packages neededimport "github.com/labstack/echo/v5/middleware"
e.Use(middleware.RequestLogger()) // request log via log/sloge.Use(middleware.Recover()) // catches panics, returns 500e.Use(middleware.CORS()) // default: allows all origins
// Restrict CORS to specific origins:e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ AllowOrigins: []string{"https://example.com"}, AllowMethods: []string{http.MethodGet, http.MethodPost},}))Echo v5 log ด้วย log/slog ของ standard library — ไม่มี logger interface ของตัวเองอีกแล้ว RequestLogger() ใช้ e.Logger (เป็น *slog.Logger) ถ้าอยากเลือก field เอง ใช้ RequestLoggerWithConfig แล้ว log ค่าเองแบบนี้:
e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{ LogStatus: true, LogURI: true, LogValuesFunc: func(c *echo.Context, v middleware.RequestLoggerValues) error { slog.Info("request", "uri", v.URI, "status", v.Status) return nil },}))ลำดับ middleware
หัวข้อที่มีชื่อว่า “ลำดับ middleware”เหมือน Express ลำดับมีความสำคัญ middleware ที่ลงทะเบียนก่อนจะทำงานก่อน RequestLogger และ Recover ควรอยู่ชั้นนอกสุดเสมอ
e.Use(middleware.RequestLogger()) // 1st — log all requestse.Use(middleware.Recover()) // 2nd — catch panics from any later handlere.Use(authMiddleware) // 3rd — auth checks after logging is set upMiddleware ระดับ route และ group
หัวข้อที่มีชื่อว่า “Middleware ระดับ route และ group”ใน Express คุณส่ง middleware เข้าไปที่ route ได้ตรง ๆ ส่วน Echo ทำแบบเดียวกันได้ด้วย .Use บน group
// Express — per-route middlewareapp.get('/admin', authMiddleware, adminHandler);
// Express — router-levelconst adminRouter = express.Router();adminRouter.use(authMiddleware);adminRouter.get('/', adminHandler);app.use('/admin', adminRouter);// Echo — per-route middlewaree.GET("/admin", adminHandler, authMiddleware)
// Echo — group-level middlewareadmin := e.Group("/admin")admin.Use(authMiddleware)admin.GET("", adminHandler)admin.GET("/users", adminUsersHandler)เขียน auth middleware เอง
หัวข้อที่มีชื่อว่า “เขียน auth middleware เอง”// Express JWT-like auth middlewarefunction requireAuth(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ message: 'unauthorized' }); try { req.user = verifyToken(token); next(); } catch { res.status(401).json({ message: 'invalid token' }); }}// Echo custom auth middlewarefunc RequireAuth(next echo.HandlerFunc) echo.HandlerFunc { return func(c *echo.Context) error { header := c.Request().Header.Get("Authorization") if header == "" { return echo.NewHTTPError(http.StatusUnauthorized, "missing token") } parts := strings.SplitN(header, " ", 2) if len(parts) != 2 || parts[0] != "Bearer" { return echo.NewHTTPError(http.StatusUnauthorized, "bad token format") } claims, err := verifyToken(parts[1]) if err != nil { return echo.NewHTTPError(http.StatusUnauthorized, "invalid token") } // Store claims in context for downstream handlers c.Set("user", claims) return next(c) }}รันบนเครื่องของคุณ — ต้องการ Echo module และ network port