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

Firebase可调用函数调用时持续返回401未认证错误,请求排查方向

Firebase可调用函数调用时持续返回401未认证错误,请求排查方向

我是个编程新手,11月底才开始用AI帮自己做一个React Web应用,现在正尝试部署到生产环境。但调用Firebase可调用函数时一直碰到401未认证错误,折腾好久了,想问问大家有没有新的排查方向😭

错误信息

Failed to load resource: the server responded with a status of 401 ()
LGChat.js:78 Full error object: FirebaseError: The function must be called while authenticated.

问题现状

明明我已经完全登录了,Firebase Storage能正常拉取当前账号关联的文档,说明认证功能本身没坏——我甚至删除重建过账号,确认auth流程没问题。而且根据我对可调用函数的理解,Firebase会自动处理token的生成和传递,我代码里没做过影响token的操作,但每次调用函数时,Firebase自己生成的token发过去后还是被拒绝了,实在想不通token会有问题。

已完成的排查步骤

LLM们大多建议检查环境配置,我把它们提到的每一项都核对过了,也确认自己完全登录了Google Cloud SDK。具体做过的排查包括:

  • 仔细检查了所有可能的环境配置问题
  • 确认已登录Google Cloud
  • 对照可调用函数官方文档确认配置正确
  • 核对过gcloud密钥等信息,确保无误
  • 确认其他Firebase服务(比如Storage)能正常工作
  • 给所有用户都设置了函数调用者权限
  • 每次重新部署前都会清缓存

相关代码片段

错误是从我的functions/index.js和LGChat.js文件里抛出来的,下面是相关代码:

LGChat.js 中的函数调用代码

const processDocument = async () => {
  if (!selectedFile || isProcessing || isProcessed || !currentUser) return;

  setIsProcessing(true);
  setError(null);
  setProcessingStatus('Starting processing...');

  try {
    // Use the already initialized functions instance from above
    const processPdfDocument = httpsCallable(functions, 'processPdfDocument', {
      timeout: 540000
    });

    console.log('Processing document with auth:', {
      uid: currentUser?.uid,
      email: currentUser?.email
    });

    console.log('Document details being sent:', {
      fileId: selectedFile.id,
      fileName: selectedFile.name,
      fileUrl: selectedFile.url,
      userId: currentUser.uid
    });

    setProcessingStatus('Processing PDF...');
    console.log('Processing PDF...');
    const result = await processPdfDocument({
      fileId: selectedFile.id,
      fileName: selectedFile.name,
      fileUrl: selectedFile.url,
      userId: currentUser.uid
    });
    console.log('Processing PDF result:', result);

    if (result.data?.success) {
      setIsProcessed(true);
      setProcessingStatus(
        `Successfully processed ${result.data.pagesProcessed} pages`
      );
    } else {
      throw new Error(
        'Processing failed: ' + (result.data?.error || 'Unknown error')
      );
    }
  } catch (error) {
    console.error('Error processing document:', error);
    setError(error.message || 'Failed to process document.');
    setIsProcessed(false);
    setProcessingStatus('Processing failed');
  }
};

functions/index.js 中的可调用函数代码

// Process PDF
exports.processPdfDocument = onCall(
  {
    memory: "2GiB",
    timeoutSeconds: 540,
    cors: true,
    enforceAppCheck: false,
    secrets: [
      "OPENAI_API_KEY",
      "PINECONE_API_KEY",
      "PINECONE_INDEX_NAME",
      "PINECONE_HOST"
    ]
  }, 
  async (request, context) => {
    // Log the full context and request for debugging
    console.log("[processPdfDocument] Request data:", {
      auth: request.auth,
      rawRequest: request.rawRequest,
      data: request.data
    });

    console.log("[processPdfDocument] Context:", {
      auth: context.auth,
      rawRequest: context.rawRequest
    });

    // Check auth
    if (!request.auth) {
      console.error("[processPdfDocument] No auth context");
      throw new HttpsError(
        "unauthenticated",
        "The function must be called while authenticated."
      );
    }

    // Verify UID
    if (!request.auth.uid) {
      console.error("[processPdfDocument] No UID in auth context");
      throw new HttpsError(
        "unauthenticated",
        "Invalid authentication. Please sign in again."
      );
    }

    try {
      // Verify the token
      const decodedToken = await admin.auth().verifyIdToken(context.auth.token);
      console.log("[processPdfDocument] Token verified:", decodedToken.uid);

      console.log("[processPdfDocument] Auth context:", {
        hasAuth: Boolean(context.auth),
        uid: context.auth ? context.auth.uid : null,
        token: context.auth ? Boolean(context.auth.token) : false,
        app: Boolean(context.app)
      });

      if (!request.auth || !request.auth.uid) {
        console.error("[processPdfDocument] Authentication error: No valid auth context");
        throw new HttpsError(
          "unauthenticated",
          "The function must be called while authenticated."
        );
      }

      try {
        console.log("[processPdfDocument] Request data:", {
          ...request.data,
          auth: {uid: context.auth.uid}
        });

        const {fileId, fileName, path} = request.data;
        const uid = context.auth.uid;

        // Validate parameters with detailed logging
        const missingParams = [];
        if (!fileId) missingParams.push("fileId");
        if (!fileName) missingParams.push("fileName");
        if (!path) missingParams.push("path");

        if (missingParams.length > 0) {
          const errorMsg = `Missing required parameters: ${missingParams.join(", ")}`;
          console.error("[processPdfDocument] Parameter validation failed:", {
            received: {fileId, fileName, path},
            missing: missingParams
          });
          throw new HttpsError("invalid-argument", errorMsg);
        }

        // Validate config with error handling
        let config;
        try {
          config = getConfig();
          console.log("[processPdfDocument] Configuration validated successfully");
        } catch (configError) {
          console.error("[processPdfDocument] Configuration error:", configError);
          throw new HttpsError(
            "failed-precondition",
            `Configuration error: ${configError.message}`
          );
        }

        // Initialize storage and get file
        const storage = getStorage();
        const bucket = storage.bucket();
        const tempFilePath = `/tmp/${fileId}-${Date.now()}.pdf`;

        // Download file with detailed error handling
        try {
          console.log("[processPdfDocument] Attempting to download file:", {path, tempFilePath});
          await bucket.file(path).download({destination: tempFilePath});
          console.log("[processPdfDocument] File downloaded successfully");
        } catch (downloadError) {
          console.error("[processPdfDocument] Download error:", {
            error: downloadError,
            path,
            tempFilePath
          });
          throw new HttpsError(
            "internal",
            `Failed to download file: ${downloadError.message}`
          );
        }

        // Process PDF with error handling
        let pdfContent;
        try {
          const dataBuffer = await fs.readFile(tempFilePath);
          console.log("[processPdfDocument] File read successfully, size:", dataBuffer.length);
          
          pdfContent = await pdf(dataBuffer, {
            pageNumbers: true,
            normalizeWhitespace: true,
            disableCombineTextItems: false
          });
          console.log("[processPdfDocument] PDF parsed successfully, pages:", pdfContent.numpages);
        } catch (pdfError) {
          console.error("[processPdfDocument] PDF processing error:", pdfError);
          throw new HttpsError(
            "internal",
            `Failed to process PDF: ${pdfError.message}`
          );
        }

        // Create text chunks
        const splitter = new RecursiveCharacterTextSplitter({
          chunkSize: 1000,
          chunkOverlap: 200
        });

        let allDocs = [];
        try {
          const docs = await splitter.createDocuments(
            [pdfContent.text],
            [{
              pageNumber: 1,
              fileId,
              fileName,
              userId: uid
            }]
          );
          allDocs = docs;
          console.log("[processPdfDocument] Created chunks:", allDocs.length);
        } catch (splitError) {
          console.error("[processPdfDocument] Text splitting error:", splitError);
          throw new HttpsError(
            "internal",
            `Failed to split text: ${splitError.message}`
          );
        }
      } catch (innerError) {
        throw innerError;
      }
    } catch (outerError) {
      throw outerError;
    }
  }
);

我实在没辙了,有没有大佬能给指个新方向?因为是新手,麻烦尽量讲得直白些,我可能听不懂太专业的术语😭 如果需要我提供更多信息,也请随时说!

备注:内容来源于stack exchange,提问作者user29219329

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 14:04:31