Files
pangolin/server/internal/httpapi/cors_test.go
T
wangjia 3d521973ab
Deploy Server / deploy-server (push) Successful in 2m56s
feat(server): CORS 中间件(Web 用户中心跨域调 /v1/*)
usercenter(app.yanmeiai.com,浏览器)跨域调控制面 API 会被浏览器拦(无 CORS 头)。
加白名单 CORS 中间件(CORS_ORIGINS,缺省 app.yanmeiai.com + pages.dev),应答 OPTIONS
预检。原生端非浏览器不受影响。Bearer 认证故不需 Allow-Credentials。含 3 项测试。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
2026-07-06 21:52:33 +08:00

48 lines
1.4 KiB
Go

package httpapi
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestCORS(t *testing.T) {
t.Setenv("CORS_ORIGINS", "https://app.yanmeiai.com")
mw := NewCORS()
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(200) })
h := mw(next)
// 允许的 Origin:补 Allow-Origin,普通请求继续。
r := httptest.NewRequest("POST", "/v1/auth/login", nil)
r.Header.Set("Origin", "https://app.yanmeiai.com")
w := httptest.NewRecorder()
h.ServeHTTP(w, r)
if got := w.Header().Get("Access-Control-Allow-Origin"); got != "https://app.yanmeiai.com" {
t.Fatalf("allowed origin: want header, got %q", got)
}
if w.Code != 200 {
t.Fatalf("non-preflight should reach next, got %d", w.Code)
}
// OPTIONS 预检:204,不落到业务。
r = httptest.NewRequest("OPTIONS", "/v1/auth/login", nil)
r.Header.Set("Origin", "https://app.yanmeiai.com")
w = httptest.NewRecorder()
h.ServeHTTP(w, r)
if w.Code != http.StatusNoContent {
t.Fatalf("preflight: want 204, got %d", w.Code)
}
if w.Header().Get("Access-Control-Allow-Methods") == "" {
t.Fatalf("preflight missing Allow-Methods")
}
// 未白名单 Origin:不补 Allow-Origin。
r = httptest.NewRequest("POST", "/v1/auth/login", nil)
r.Header.Set("Origin", "https://evil.example.com")
w = httptest.NewRecorder()
h.ServeHTTP(w, r)
if got := w.Header().Get("Access-Control-Allow-Origin"); got != "" {
t.Fatalf("disallowed origin should get no header, got %q", got)
}
}