You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署带--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",
    };
  });

问题原因

  1. Callable函数与普通HTTP函数的差异:TS代码用的是Firebase专属的onCall类型函数,Firebase会自动处理CORS、认证令牌传递、请求响应格式转换等逻辑;而Go写的是普通HTTP函数,前端用httpsCallable调用时,请求流程和格式不匹配。
  2. 预检请求被认证拦截:启用--no-allow-unauthenticated后,Firebase会在函数执行前先验证认证令牌。但浏览器自动发起的OPTIONS预检请求不会携带Authorization头,会被Firebase的认证拦截直接拒绝,根本到不了Go函数的CORS处理逻辑,因此触发CORS错误。
  3. 请求格式不兼容: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:23:12