Slim

CORS 中间件

CORS (Cross-Origin Resource Sharing) 中间件用于处理跨域资源共享,允许您控制哪些域可以访问您的 API 资源。

使用方法

基础用法

import (    "go-slim.dev/slim"    "go-slim.dev/slim/middleware")func main() {    s := slim.New()    // 使用默认配置    s.Use(middleware.CORS())    s.GET("/api/users", func(c slim.Context) error {        return c.JSON(200, map[string]string{"message": "Hello"})    })    s.Start(":8080")}

自定义配置

s := slim.New()s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins:     []string{"https://example.com", "https://app.example.com"},    AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},    AllowHeaders:     []string{"Content-Type", "Authorization"},    AllowCredentials: true,    ExposeHeaders:    []string{"X-Request-ID"},    MaxAge:           3600,}))

配置选项

CORSConfig

type CORSConfig struct {    // AllowOrigins 定义允许访问资源的源列表    // 可选。默认值 []string{"*"}    AllowOrigins []string    // AllowOriginFunc 是一个自定义函数,用于验证源    // 如果设置此选项,AllowOrigins 将被忽略    // 可选    AllowOriginFunc func(origin string) (bool, error)    // AllowMethods 定义访问资源时允许的 HTTP 方法列表    // 用于响应预检请求    // 可选。默认值包含常用方法    AllowMethods []string    // AllowHeaders 定义实际请求中可以使用的请求头列表    // 用于响应预检请求    // 可选。默认值 []string{}    AllowHeaders []string    // AllowCredentials 指示当凭证标志为 true 时,    // 是否可以暴露对请求的响应    // 可选。默认值 false    AllowCredentials bool    // ExposeHeaders 定义客户端允许访问的响应头白名单    // 可选。默认值 []string{}    ExposeHeaders []string    // MaxAge 指示预检请求的结果可以被缓存多长时间(秒)    // 可选。默认值 0    MaxAge int}

使用示例

1. 允许所有源(开发环境)

s.Use(middleware.CORS())

默认配置允许所有源访问(AllowOrigins: []string{"*"}),适合开发环境。

2. 限制特定域名

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins: []string{        "https://example.com",        "https://app.example.com",    },}))

3. 使用通配符模式

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins: []string{        "https://*.example.com",  // 允许所有 example.com 的子域名        "http://localhost:*",      // 允许 localhost 的所有端口    },}))

4. 自定义源验证函数

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOriginFunc: func(origin string) (bool, error) {        // 自定义逻辑,例如从数据库查询        allowedOrigins := []string{            "https://example.com",            "https://app.example.com",        }        for _, allowed := range allowedOrigins {            if origin == allowed {                return true, nil            }        }        return false, nil    },}))

5. 支持凭证(Cookie)

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins:     []string{"https://example.com"},    AllowCredentials: true,    AllowHeaders:     []string{"Content-Type", "Authorization"},}))

注意:当 AllowCredentials: true 时,AllowOrigins 不能设置为 ["*"],必须指定具体的域名。

6. 完整配置示例

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins: []string{        "https://example.com",        "https://app.example.com",    },    AllowMethods: []string{        "GET",        "POST",        "PUT",        "PATCH",        "DELETE",        "OPTIONS",    },    AllowHeaders: []string{        "Origin",        "Content-Type",        "Accept",        "Authorization",        "X-Request-ID",    },    ExposeHeaders: []string{        "X-Request-ID",        "X-Response-Time",    },    AllowCredentials: true,    MaxAge:           3600, // 1 小时}))

工作原理

简单请求

对于简单请求(Simple Request),CORS 中间件会:

  1. 检查请求的 Origin
  2. 验证源是否在允许列表中
  3. 如果允许,设置 Access-Control-Allow-Origin 响应头
  4. 如果配置了 AllowCredentials,设置相应的响应头
  5. 继续处理请求

预检请求

对于预检请求(Preflight Request,HTTP OPTIONS),CORS 中间件会:

  1. 检查请求的 Origin
  2. 验证源是否在允许列表中
  3. 设置 Access-Control-Allow-Origin
  4. 设置 Access-Control-Allow-Methods
  5. 设置 Access-Control-Allow-Headers
  6. 如果配置了 MaxAge,设置 Access-Control-Max-Age
  7. 返回 204 No Content 状态码

默认配置

CORSConfig{    AllowOrigins: []string{"*"},    AllowMethods: []string{        "GET",        "HEAD",        "PUT",        "PATCH",        "POST",        "DELETE",    },    AllowHeaders:     []string{},    AllowCredentials: false,    ExposeHeaders:    []string{},    MaxAge:           0,}

最佳实践

1. 生产环境限制源

// 开发环境if os.Getenv("ENV") == "development" {    s.Use(middleware.CORS())} else {    // 生产环境    s.Use(middleware.CORSWithConfig(middleware.CORSConfig{        AllowOrigins: []string{            "https://yourdomain.com",            "https://app.yourdomain.com",        },        AllowCredentials: true,    }))}

2. 使用环境变量配置

allowedOrigins := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    AllowOrigins: allowedOrigins,}))

3. 限制暴露的响应头

只暴露客户端真正需要的响应头:

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    ExposeHeaders: []string{        "X-Request-ID",        "X-Total-Count", // 分页时可能需要    },}))

4. 合理设置 MaxAge

设置合理的缓存时间可以减少预检请求的数量:

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{    MaxAge: 86400, // 24 小时}))

安全考虑

  1. 不要在生产环境使用 AllowOrigins: ["*"],这会允许任何网站访问您的 API

  2. 谨慎使用 AllowCredentials: true,确保您了解其安全影响

  3. 限制 AllowMethods,只允许必要的 HTTP 方法

  4. 限制 AllowHeaders,只允许必要的请求头

  5. 使用 HTTPS,避免在不安全的连接上传输敏感信息

常见问题

Q: 为什么 CORS 请求失败?

A: 检查以下几点:

  • 服务器是否正确配置了 CORS 中间件
  • AllowOrigins 是否包含客户端的域名
  • 如果使用凭证(Cookie),是否设置了 AllowCredentials: true
  • 是否正确设置了 AllowHeadersAllowMethods

Q: 什么是预检请求?

A: 预检请求是浏览器在发送某些跨域请求前自动发送的 OPTIONS 请求,用于检查服务器是否允许实际请求。

Q: AllowOrigins: ["*"]AllowCredentials: true 能同时使用吗?

A: 不能。出于安全考虑,当启用凭证时,必须指定具体的源,不能使用通配符 *

参考资料

切换 选择 esc 关闭搜索