137 lines
3.4 KiB
Go
137 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"net/url"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gin-contrib/cors"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var serviceMap = map[string]string{
|
|
"/user/login": "http://user_login:80",
|
|
"/user/register": "http://user_register:80",
|
|
"/user/delete": "http://user_delete:80",
|
|
"/user/update/account": "http://user_update_account:80",
|
|
"/user/update/password": "http://user_update_password:80",
|
|
}
|
|
|
|
// 日志中间件(记录网关接收的请求)
|
|
func loggerMiddleware() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
startTime := time.Now()
|
|
c.Next()
|
|
endTime := time.Now()
|
|
|
|
log.Printf(
|
|
"[网关请求] %s %s | 状态码: %d | 耗时: %s | 客户端IP: %s",
|
|
c.Request.Method,
|
|
c.Request.URL.Path,
|
|
c.Writer.Status(),
|
|
endTime.Sub(startTime),
|
|
c.ClientIP(),
|
|
)
|
|
}
|
|
}
|
|
|
|
// 反向代理处理(添加详细转发日志)
|
|
func reverseProxy(target string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
// 解析目标服务地址
|
|
targetURL, err := url.Parse(target)
|
|
if err != nil {
|
|
log.Printf("[代理错误] 目标服务地址解析失败: %s, 错误: %v", target, err)
|
|
c.JSON(http.StatusInternalServerError, gin.H{
|
|
"success": false,
|
|
"message": "服务配置错误",
|
|
})
|
|
return
|
|
}
|
|
|
|
// 创建反向代理实例
|
|
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
|
|
|
// 记录转发前的请求信息
|
|
reqStart := time.Now()
|
|
log.Printf(
|
|
"[开始转发] 方法: %s | 原始路径: %s | 目标服务: %s | 客户端IP: %s",
|
|
c.Request.Method,
|
|
c.Request.URL.Path,
|
|
targetURL.String(),
|
|
c.ClientIP(),
|
|
)
|
|
|
|
// 自定义请求转发逻辑(并记录请求头)
|
|
originalDirector := proxy.Director
|
|
proxy.Director = func(req *http.Request) {
|
|
originalDirector(req)
|
|
// 传递关键头信息
|
|
req.Header.Set("Origin", c.Request.Header.Get("Origin"))
|
|
req.Host = targetURL.Host
|
|
req.Header.Set("X-Forwarded-By", "user-gateway")
|
|
|
|
// 打印转发的请求头(调试用,生产环境可注释)
|
|
log.Printf("[转发请求头] 目标服务: %s | Origin: %s | Host: %s",
|
|
targetURL.Host,
|
|
req.Header.Get("Origin"),
|
|
req.Host,
|
|
)
|
|
}
|
|
|
|
// 记录响应信息
|
|
proxy.ModifyResponse = func(resp *http.Response) error {
|
|
// 计算转发耗时
|
|
proxyDuration := time.Since(reqStart)
|
|
|
|
// 打印响应状态
|
|
log.Printf(
|
|
"[转发响应] 目标服务: %s | 状态码: %d | 耗时: %s | 响应头Origin: %s",
|
|
targetURL.Host,
|
|
resp.StatusCode,
|
|
proxyDuration,
|
|
resp.Header.Get("Access-Control-Allow-Origin"),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
// 执行代理转发
|
|
proxy.ServeHTTP(c.Writer, c.Request)
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
r := gin.Default()
|
|
|
|
// 注册日志中间件
|
|
r.Use(loggerMiddleware())
|
|
|
|
// 跨域配置
|
|
r.Use(cors.New(cors.Config{
|
|
AllowOrigins: []string{"*"},
|
|
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
|
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"},
|
|
ExposeHeaders: []string{"Content-Length"},
|
|
AllowCredentials: true,
|
|
MaxAge: 12 * time.Hour,
|
|
}))
|
|
|
|
// 注册路由
|
|
for path, target := range serviceMap {
|
|
r.Any(path, reverseProxy(target))
|
|
r.Any(path+"/*any", reverseProxy(target))
|
|
}
|
|
|
|
// 启动服务
|
|
port := os.Getenv("GATEWAY_PORT")
|
|
if port == "" {
|
|
port = "80"
|
|
}
|
|
log.Printf("网关服务启动在 %s 端口", port)
|
|
if err := r.Run(":" + port); err != nil {
|
|
log.Fatalf("服务启动失败: %v", err)
|
|
}
|
|
} |