Gin 框架 CORS 策略笔记
什么是 CORS
CORS(跨域资源共享)是浏览器的一种安全机制,用于限制一个网页从不同的域请求资源。默认情况下,浏览器会阻止跨域请求,除非服务器明确允许跨域访问。
在使用 Gin 框架开发 API 时,如果前端页面和后端 API 不在同一个域或端口下,就需要配置 CORS 以解决跨域问题。
Gin 中处理 CORS 的方法
1. 使用 github.com/gin-contrib/cors
中间件
Gin 提供了一个官方推荐的 CORS 中间件,可以通过简单配置实现跨域支持。
安装中间件
go get github.com/gin-contrib/cors
示例代码
package main
import (
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"time"
)
func main() {
r := gin.Default()
// 配置 CORS 中间件
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://example.com", "http://localhost:3000"}, // 允许的源
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, // 允许的方法
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"}, // 允许的头
ExposeHeaders: []string{"Content-Length"}, // 可见的头
AllowCredentials: true, // 允许携带凭据
MaxAge: 12 * time.Hour, // 缓存时间
}))
// 示例路由
r.GET("/api/test", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "CORS is configured!",
})
})
// 启动服务
r.Run(":8080")
}
2. 手动设置 CORS Headers
如果不想使用第三方中间件,可以手动设置跨域响应头。
示例代码
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
// 自定义中间件处理 CORS
r.Use(func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "*") // 允许所有域
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Origin, Content-Type, Authorization")
c.Writer.Header().Set("Access-Control-Expose-Headers", "Content-Length")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(http.StatusNoContent)
return
}
c.Next()
})
// 示例路由
r.GET("/api/test", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "CORS is configured manually!",
})
})
r.Run(":8080")
}
配置选项说明
1. AllowOrigins
- 含义:允许的请求来源列表。
- 类型:
[]string
示例:
AllowOrigins: []string{"http://example.com", "http://localhost:3000"}
注意:
- 不建议在生产环境中使用通配符
*
,除非非常确定不需要限制来源。
- 不建议在生产环境中使用通配符
2. AllowMethods
- 含义:允许的 HTTP 方法。
- 类型:
[]string
示例:
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}
3. AllowHeaders
- 含义:允许的请求头。
- 类型:
[]string
示例:
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"}
说明:
- 如果前端发送请求包含自定义头,必须在这里显式允许,否则会被浏览器拦截。
4. ExposeHeaders
- 含义:允许前端访问的响应头。
- 类型:
[]string
示例:
ExposeHeaders: []string{"Content-Length"}
5. AllowCredentials
- 含义:是否允许跨域请求携带凭据(如 Cookies)。
- 类型:
bool
示例:
AllowCredentials: true
6. MaxAge
- 含义:预检请求的缓存时间。
- 类型:
time.Duration
示例:
MaxAge: 12 * time.Hour
注意事项
- 开发环境配置宽松:可以使用通配符
*
允许所有来源和头,以方便调试。 - 生产环境配置严格:仅允许特定的域名、方法和头,以减少安全风险。
OPTIONS 请求:
- 浏览器会在某些情况下(如非简单请求)自动发送预检请求(OPTIONS)。
- 需要处理好预检请求并返回正确的跨域响应头。
安全性:
- 不随意允许所有来源(
*
)。 - 避免在生产中启用
AllowCredentials
与*
的组合,可能导致安全问题。
- 不随意允许所有来源(
常见问题
1. 为什么前端仍然报跨域错误?
- 可能是 CORS 配置不正确,特别是
AllowOrigins
和AllowHeaders
。 - 检查是否正确返回了
Access-Control-Allow-Origin
和其他相关头。
2. 如何调试跨域问题?
- 使用浏览器开发者工具查看请求和响应头,确认是否包含正确的 CORS 头。
- 在后端日志中检查是否正确处理了 OPTIONS 请求。
3. 通配符 *
和携带凭据的限制
- 如果
AllowCredentials
设置为true
,则AllowOrigins
不能是*
,必须指定具体的域名。
通过以上配置和说明,你可以在 Gin 框架中灵活处理跨域问题。如果有特殊需求,可以进一步调整设置。