Gin 跨域中间件配置

浏览器同源策略限制跨域请求,前后端分离部署时需要后端返回 CORS 响应头。这里提供两个 Gin 中间件:一个按白名单放行,一个放行所有来源。

方式一:白名单校验(推荐)

只有 originDomains 中配置的来源才允许跨域:

 1package handler
 2
 3import (
 4	"github.com/gin-gonic/gin"
 5	"net/http"
 6)
 7
 8func Cors() gin.HandlerFunc {
 9	return func(c *gin.Context) {
10		method := c.Request.Method               // 请求方法
11		origin := c.Request.Header.Get("Origin") // 请求头部
12		originDomains := []string{"http://localhost:3000"}
13		inArraysFlag := false
14		for _, value := range originDomains {
15			if origin == value {
16				inArraysFlag = true
17				break
18			}
19		}
20		if origin != "" && inArraysFlag {
21			// 只允许白名单内的来源跨域访问
22			c.Header("Access-Control-Allow-Origin", origin)
23			// 服务器支持的所有跨域请求的方法,为了避免浏览器多次发起"预检"请求
24			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
25			// 允许的请求头类型
26			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
27			// 允许浏览器读取的自定义响应头
28			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar")
29			// 预检结果的缓存时间,单位为秒,避免重复发起预检请求
30			c.Header("Access-Control-Max-Age", "172800")
31			// 跨域请求是否需要携带 cookie 信息
32			c.Header("Access-Control-Allow-Credentials", "false")
33			c.Set("content-type", "application/json")
34		}
35		// 放行所有 OPTIONS 预检请求
36		if method == "OPTIONS" {
37			c.JSON(http.StatusOK, "Options Request!")
38		}
39		// 处理请求
40		c.Next()
41	}
42}

方式二:放行所有来源

内网环境或调试时可以使用更宽松的版本,直接回显请求的 Origin

 1func CorsHandler() gin.HandlerFunc {
 2	return func(c *gin.Context) {
 3		method := c.Request.Method
 4		origin := c.Request.Header.Get("Origin")
 5		if origin != "" {
 6			c.Header("Access-Control-Allow-Origin", origin)
 7			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE")
 8			c.Header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
 9			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Cache-Control, Content-Language, Content-Type")
10			c.Header("Access-Control-Allow-Credentials", "false")
11			c.Set("content-type", "application/json")
12		}
13		if method == "OPTIONS" {
14			c.AbortWithStatus(http.StatusNoContent)
15		}
16		c.Next()
17	}
18}

使用时挂在路由上即可:

1r := gin.Default()
2r.Use(Cors())

注意:Access-Control-Allow-Origin 设为 * 时不能同时开启 Allow-Credentials,需要携带 cookie 的场景要像方式一那样回显具体 Origin。