部署带--no-allow-unauthenticated的Go版二代Cloud Function遇CORS错误求助
Go实现第二代Firebase Cloud Function的CORS与认证问题
部署时添加--no-allow-unauthenticated参数会触发CORS错误;禁用认证(使用--allow-unauthenticated)部署时,能看到请求携带Bearer令牌的Authorization Cookie。
Go函数实现代码
func FntTestingWithAuth(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") // Set Cors in OPTIONS call if r.Method == http.MethodOptions { w.Header().Set("Access-Control-Allow-Methods", "*") w.Header().Set("Access-Control-Allow-Headers", "*") //w.Header().Set("Access-Control-Max-Age", "3600") w.WriteHeader(http.StatusNoContent) fmt.Println("OPTIONS EXECUTED so return back!!!!!") return } fmt.Printf("[%s] has been EXECUTED!!!!!", r.Method) }
前端调用代码
const testingFn = httpsCallable(functions(), "testing"); testingFn(requestParams).then((result) => { alert(result.data); }) .catch((error) => { alert(error); });
对比用TypeScript实现的正常代码
functions .runWith({ }) .https .onCall(async (data, context) => { return { "response": "working", }; });
问题原因
- Callable函数与普通HTTP函数的差异:TS代码用的是Firebase专属的
onCall类型函数,Firebase会自动处理CORS、认证令牌传递、请求响应格式转换等逻辑;而Go写的是普通HTTP函数,前端用httpsCallable调用时,请求流程和格式不匹配。 - 预检请求被认证拦截:启用
--no-allow-unauthenticated后,Firebase会在函数执行前先验证认证令牌。但浏览器自动发起的OPTIONS预检请求不会携带Authorization头,会被Firebase的认证拦截直接拒绝,根本到不了Go函数的CORS处理逻辑,因此触发CORS错误。 - 请求格式不兼容:
httpsCallable发送的请求有特定JSON结构(如包含data字段),Go函数未适配该格式,虽不是CORS直接原因,但会影响后续业务逻辑。
解决办法
方案一:让Go函数适配Callable函数规范
Firebase Callable函数有固定的请求响应格式,需要在Go函数中实现:
- 解析请求body中的
data字段 - 从
Authorization头提取Bearer令牌,调用Firebase Admin SDK验证令牌有效性 - 响应返回
{"result": ...}结构的JSON - 确保OPTIONS请求绕过认证(因为预检不携带令牌),可通过中间件或函数配置实现
方案二:前端改用普通fetch调用
放弃httpsCallable,用fetch手动携带认证令牌:
fetch('https://your-function-url', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${await getAuth().currentUser.getIdToken()}` }, body: JSON.stringify(requestParams) }) .then(res => res.json()) .then(data => alert(data)) .catch(err => alert(err));
Go函数保留现有CORS处理逻辑即可,预检请求会被函数正常处理,实际请求携带令牌可通过Firebase认证拦截。
方案三:添加认证中间件处理预检与验证
在Go函数中添加中间件,跳过OPTIONS请求的认证,同时验证实际请求的令牌:
import ( "strings" "net/http" "context" firebase "firebase.google.com/go/v4" "firebase.google.com/go/v4/auth" ) func authMiddleware(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { // 直接处理OPTIONS预检请求 if r.Method == http.MethodOptions { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "*") w.Header().Set("Access-Control-Allow-Headers", "*") w.WriteHeader(http.StatusNoContent) return } // 验证Bearer令牌 authHeader := r.Header.Get("Authorization") if authHeader == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } token := strings.TrimPrefix(authHeader, "Bearer ") app, _ := firebase.NewApp(context.Background(), nil) client, _ := app.Auth(context.Background()) _, err := client.VerifyIDToken(context.Background(), token) if err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } next(w, r) } } // 注册函数时使用中间件 func main() { http.HandleFunc("/testing", authMiddleware(FntTestingWithAuth)) // 启动服务逻辑 }
启用--no-allow-unauthenticated后,OPTIONS请求会被中间件直接处理返回CORS头,实际请求会完成令牌验证后进入业务逻辑。
内容的提问来源于stack exchange,提问作者angelcervera
相关产品推荐
相关产品推荐

