3分钟实现完美的跨域解决方案 - Go CORS中间件详解

21 阅读3分钟

前言

在前后端分离的开发中,跨域问题一直是让开发者头疼的问题。今天我将分享一个基于 Gin 框架的 CORS 中间件实现,它提供了两种模式:全局放行和白名单控制,让跨域配置变得简单而安全。

核心功能

  1. 支持全局跨域放行
  2. 支持白名单模式
  3. 灵活的配置选项
  4. 健康检查接口豁免

实现方案

1. 配置文件设置

首先在配置文件中定义 CORS 相关配置:

cors:
  mode: "strict-whitelist"  # 可选: allow-all, strict-whitelist
  whitelist:
    - allow-origin: "http://localhost:8080"
      allow-headers: "Content-Type,AccessToken,X-CSRF-Token,Authorization,Token"
      allow-methods: "POST,GET,OPTIONS,DELETE,PUT"
      expose-headers: "Content-Length,Access-Control-Allow-Origin,Access-Control-Allow-Headers"
      allow-credentials: true

2. 使用方法

在 main.go 中注册中间件:

package main

import (
    "github.com/gin-gonic/gin"
    "your-project/middleware"
)

func main() {
    r := gin.Default()
    
    // 使用CORS中间件
    r.Use(middleware.CorsByRules())
    
    // 路由配置
    r.GET("/api/users", func(c *gin.Context) {
        c.JSON(200, gin.H{"message": "success"})
    })
    
    r.Run(":8080")
}

3. 两种使用模式

模式一:全局放行

适合开发环境或者简单应用:

// config.yaml
cors:
  mode: "allow-all"

这种模式会允许所有跨域请求,配置简单,但安全性较低。

模式二:白名单模式

适合生产环境:

// config.yaml
cors:
  mode: "strict-whitelist"
  whitelist:
    - allow-origin: "https://your-frontend.com"
      allow-methods: "GET,POST,PUT,DELETE"
      allow-credentials: true

这种模式只允许配置中指定的域名访问,安全性高。

实现细节解析

1. 全局放行模式

func Cors() gin.HandlerFunc {
    return func(c *gin.Context) {
        origin := c.Request.Header.Get("Origin")
        c.Header("Access-Control-Allow-Origin", origin)
        c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization")
        c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT")
        c.Header("Access-Control-Allow-Credentials", "true")
        
        if c.Request.Method == "OPTIONS" {
            c.AbortWithStatus(http.StatusNoContent)
            return
        }
        c.Next()
    }
}

2. 白名单模式

func CorsByRules() gin.HandlerFunc {
    return func(c *gin.Context) {
        origin := c.GetHeader("origin")
        whitelist := checkCors(origin)
        
        if whitelist != nil {
            // 设置允许的跨域信息
            c.Header("Access-Control-Allow-Origin", whitelist.AllowOrigin)
            c.Header("Access-Control-Allow-Headers", whitelist.AllowHeaders)
            c.Header("Access-Control-Allow-Methods", whitelist.AllowMethods)
            // ... 其他header设置
        }
        
        // 处理OPTIONS请求
        if c.Request.Method == http.MethodOptions {
            c.AbortWithStatus(http.StatusNoContent)
            return
        }
        
        c.Next()
    }
}

特色功能

1. 健康检查接口豁免

即使在严格模式下,健康检查接口也可以被访问:

if whitelist == nil && mode == "strict-whitelist" && 
   !(c.Request.Method == "GET" && c.Request.URL.Path == "/health") {
    c.AbortWithStatus(http.StatusForbidden)
}

2. 灵活的Header配置

支持自定义允许的Headers:

c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id")

3. 支持Cookie跨域

通过配置允许携带认证信息:

c.Header("Access-Control-Allow-Credentials", "true")

最佳实践

1. 开发环境配置

cors:
  mode: "allow-all"  # 开发环境下使用全局放行

2. 生产环境配置

cors:
  mode: "strict-whitelist"
  whitelist:
    - allow-origin: "https://prod.your-site.com"
      allow-methods: "GET,POST,PUT,DELETE"
      allow-credentials: true
    - allow-origin: "https://admin.your-site.com"
      allow-methods: "GET,POST"
      allow-credentials: true

3. 前端调用示例

// axios配置
axios.defaults.withCredentials = true; // 允许携带cookie
const api = axios.create({
    baseURL: 'http://your-api.com',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + token
    }
});

安全建议

  1. 生产环境必须使用白名单模式
  2. 定期审查白名单配置
  3. 只允许必要的HTTP方法
  4. 谨慎配置 Allow-Credentials
  5. 使用HTTPS协议

性能优化

  1. 使用缓存存储白名单配置
  2. OPTIONS请求快速响应
  3. 避免复杂的判断逻辑

总结

这个CORS中间件设计简洁而强大,既可以在开发环境中快速使用,也能在生产环境中提供安全可靠的跨域控制。通过合理的配置,可以轻松解决前后端分离开发中的跨域问题。

参考资料

希望这篇文章能帮助你更好地理解和使用CORS中间件!如果有任何问题,欢迎在评论区讨论。