routing
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
)
|
||||
|
||||
func RequestID() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
id := c.Request().Header.Get(echo.HeaderXRequestID)
|
||||
if id == "" {
|
||||
id = newRequestID()
|
||||
}
|
||||
c.Response().Header().Set(echo.HeaderXRequestID, id)
|
||||
c.Set(echo.HeaderXRequestID, id)
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newRequestID() string {
|
||||
var buf [16]byte
|
||||
if _, err := rand.Read(buf[:]); err != nil {
|
||||
return fmt.Sprintf("req-%d", time.Now().UnixNano())
|
||||
}
|
||||
return hex.EncodeToString(buf[:])
|
||||
}
|
||||
|
||||
func RealIP() echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
if forwarded := c.Request().Header.Get("X-Forwarded-For"); forwarded != "" {
|
||||
c.Set("real_ip", forwarded)
|
||||
} else if host, _, err := net.SplitHostPort(c.Request().RemoteAddr); err == nil {
|
||||
c.Set("real_ip", host)
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func AccessLog(logger *slog.Logger) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
start := time.Now()
|
||||
err := next(c)
|
||||
session := GetSession(c)
|
||||
customerID := int64Value(session.CustomerID)
|
||||
cartID := int64Value(session.CartID)
|
||||
|
||||
logger.Info("request complete",
|
||||
"method", c.Request().Method,
|
||||
"path", c.Request().URL.Path,
|
||||
"status", c.Response().Status,
|
||||
"latency_ms", time.Since(start).Milliseconds(),
|
||||
"request_id", c.Response().Header().Get(echo.HeaderXRequestID),
|
||||
"parse_status", session.ParseStatus,
|
||||
"customer_id", customerID,
|
||||
"cart_id", cartID,
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Recover(logger *slog.Logger) echo.MiddlewareFunc {
|
||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
return func(c echo.Context) error {
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
logger.Error("panic recovered", "error", recovered, "stack", string(debug.Stack()))
|
||||
_ = c.JSON(http.StatusInternalServerError, map[string]string{"error": "internal server error"})
|
||||
}
|
||||
}()
|
||||
return next(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func HTTPErrorHandler(logger *slog.Logger) echo.HTTPErrorHandler {
|
||||
return func(err error, c echo.Context) {
|
||||
if c.Response().Committed {
|
||||
return
|
||||
}
|
||||
|
||||
var httpErr *echo.HTTPError
|
||||
code := http.StatusInternalServerError
|
||||
message := map[string]string{"error": "internal server error"}
|
||||
|
||||
if errors.As(err, &httpErr) {
|
||||
code = httpErr.Code
|
||||
if msg, ok := httpErr.Message.(string); ok {
|
||||
message = map[string]string{"error": msg}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Error("request failed", "status", code, "error", err)
|
||||
_ = c.JSON(code, message)
|
||||
}
|
||||
}
|
||||
|
||||
func int64Value(value *int64) any {
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
return *value
|
||||
}
|
||||
Reference in New Issue
Block a user