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

Firebase托管应用调用Python云函数:on_call失败及认证方案咨询

Firebase云函数调用问题:on_call报错与on_request认证实现

问题背景

从Firebase托管应用调用Python编写的Firebase云函数时,@https_fn.on_request()装饰的函数可通过fetch正常调用,但@https_fn.on_call()装饰的函数调用报错,同时需要为on_request函数实现认证功能。

代码示例

Python云函数(函数名:function-hw,入口:say_hello)

import functions_framework
from firebase_functions import https_fn, options
from firebase_admin import auth, initialize_app
from datetime import datetime

# 需初始化Firebase Admin
initialize_app()

@https_fn.on_call(
    cors=options.CorsOptions(
        cors_origins=[r"https://jr\.mysite\.app$"],
        cors_methods=["get", "post"],
    )
)
def say_hello(req: https_fn.Request) -> https_fn.Response:
    print(req.__dict__)
    return {
        "Hello": "World!",
        "Time": "CORS!",
        "Now": datetime.now()
    }

JS调用代码

import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-auth.js";
import { getFunctions, httpsCallable } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-functions.js";

const firebaseConfig = {
  apiKey: "...",
  authDomain: "...",
  projectId: "...",
  storageBucket: "...",
  messagingSenderId: "...",
  appId: "...",
  measurementId: "..."
};

const firebaseApp = initializeApp(firebaseConfig);
const auth = getAuth(firebaseApp);
const functions = getFunctions(firebaseApp);
var callFunction = httpsCallable('function-hw'); // 此处存在错误
callFunction()
  .then(function(result) {
    console.log(result.data);
  })
  .catch(function(error) {
    console.error('Error:', error);
  });

async function requestFunction() {
  const fcnUrl = "url for firebase function with on_request decorator";
  const response = await fetch(fcnUrl);
  const data = await response.json();
  console.log(data);
}
requestFunction()

报错信息

on_call调用时报错:

service.ts:185 Uncaught TypeError: e._url is not a function
at call (service.ts:185:59)
at service.ts:215:3
at index.js:37:1

问题解答

1. on_call云函数的使用错误

存在两处关键错误:

  • JS调用参数缺失:httpsCallable方法必须传入functions实例作为第一个参数,正确写法为:
    const callFunction = httpsCallable(functions, 'function-hw');
    
  • Python函数参数类型错误:@https_fn.on_call装饰的函数,接收的参数应为https_fn.CallableRequest而非https_fn.Request,且直接返回字典即可(无需https_fn.Response)。修正后的Python函数:
    @https_fn.on_call(
        cors=options.CorsOptions(
            cors_origins=[r"https://jr\.mysite\.app$"],
            cors_methods=["get", "post"],
        )
    )
    def say_hello(req: https_fn.CallableRequest) -> dict:
        # 可直接通过req.auth获取认证用户信息
        if req.auth:
            print(f"Authenticated user: {req.auth.uid}")
        return {
            "Hello": "World!",
            "Time": "CORS!",
            "Now": datetime.now().isoformat()
        }
    

2. on_request中实现认证

通过以下步骤实现Bearer Token认证:

前端修改:传递ID Token

在fetch请求中添加Authorization头,携带用户的ID Token:

async function requestFunction() {
  const fcnUrl = "url for firebase function with on_request decorator";
  const user = auth.currentUser;
  if (user) {
    const idToken = await user.getIdToken();
    const response = await fetch(fcnUrl, {
      headers: {
        'Authorization': `Bearer ${idToken}`
      }
    });
    const data = await response.json();
    console.log(data);
  } else {
    console.log("No user logged in");
  }
}

后端修改:验证Token

在on_request函数中提取并验证Token,获取用户信息:

@https_fn.on_request(
    cors=options.CorsOptions(
        cors_origins=[r"https://jr\.mysite\.app$"],
        cors_methods=["get", "post"],
    )
)
def say_hello(req: https_fn.Request) -> https_fn.Response:
    # 提取Authorization头
    auth_header = req.headers.get('Authorization')
    if not auth_header or not auth_header.startswith('Bearer '):
        return https_fn.Response("Unauthorized", status=401)
    
    id_token = auth_header.split('Bearer ')[1]
    try:
        # 验证ID Token
        decoded_token = auth.verify_id_token(id_token)
        uid = decoded_token['uid']
        print(f"Authenticated user UID: {uid}")
        return https_fn.Response({
            "Hello": "Authenticated World!",
            "UserUID": uid,
            "Now": datetime.now().isoformat()
        }, status=200)
    except auth.InvalidIdTokenError:
        return https_fn.Response("Invalid token", status=401)
    except Exception as e:
        return https_fn.Response(f"Error: {str(e)}", status=500)

内容的提问来源于stack exchange,提问作者John Robinson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:14:50