Files

72 lines
2.4 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package fun
import (
"strings"
"github.com/valyala/fasthttp"
)
const (
corsMaxAge = "86400" // 预检结果缓存 24h,减少浏览器 OPTIONS 探测
)
// CORS 配置跨域来源白名单,须在 Start 前调用;作用于全部端点(/cell、自定义路由与通配路由)。
// 按需放行:仅列出的来源会被放行——请求 Origin 命中白名单时回显该来源并允许
// 携带凭据(Cookie),未命中则不附加 CORS 头(浏览器侧自然拦截)。
//
// f.CORS("https://a.com", "https://b.com")
//
// 预检请求(OPTIONS 且带 Access-Control-Request-Method 头)直接以 204 应答,
// 不进入路由与 /cell 处理。
func (f *Fun) CORS(origins ...string) {
f.mustNotStarted("CORS")
whitelist := make(map[string]struct{}, len(origins))
for _, o := range origins {
if o != "" {
whitelist[strings.ToLower(o)] = struct{}{}
}
}
f.corsOrigins = whitelist
}
// corsEnabled CORS 是否已配置
func (f *Fun) corsEnabled() bool {
return len(f.corsOrigins) > 0
}
// handleCors 处理 CORS:Origin 命中白名单的请求附加跨域响应头,
// 预检请求(OPTIONS + Access-Control-Request-Method)在此直接应答并返回 true。
func (f *Fun) handleCors(fastCtx *fasthttp.RequestCtx) bool {
if !f.corsEnabled() {
return false
}
origin := string(fastCtx.Request.Header.Peek("Origin"))
if origin == "" {
return false // 同源请求与服务器到服务器调用,无跨域语义
}
if _, ok := f.corsOrigins[strings.ToLower(origin)]; !ok {
return false // 未命中白名单:不加 CORS 头,交给浏览器拦截
}
h := &fastCtx.Response.Header
h.Set("Access-Control-Allow-Origin", origin)
h.Set("Access-Control-Allow-Credentials", "true")
// 放行结果随 Origin 变化,防中间层缓存错配
h.Add("Vary", "Origin")
if !fastCtx.IsOptions() || fastCtx.Request.Header.Peek("Access-Control-Request-Method") == nil {
return false // 实际请求:头已附加,继续正常路由
}
// 预检请求:回显浏览器声明的目标方法与请求头,24h 内同请求免预检
h.Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
if reqHeaders := fastCtx.Request.Header.Peek("Access-Control-Request-Headers"); len(reqHeaders) > 0 {
h.Set("Access-Control-Allow-Headers", string(reqHeaders))
} else {
h.Set("Access-Control-Allow-Headers", "Content-Type")
}
h.Set("Access-Control-Max-Age", corsMaxAge)
fastCtx.SetStatusCode(fasthttp.StatusNoContent)
return true
}