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

跨域调用Firebase云函数时CORS错误的解决方法

跨域问题:从第三方域名调用Firebase Cloud Function时触发CORS错误

问题详情

触发函数时收到如下错误:

从源'https://admin-dashboard.3nwani.com'访问'https://uploadedfileprocessing-6d4acez4sq-uc.a.run.app/?fileURL=https://storage.googleapis.com/anwani-3b514/geojsons/lvl3/1_2_4_4_8__lvl3.json'被CORS策略阻止:请求的资源上不存在'Access-Control-Allow-Origin'头。

云函数代码

exports.uploadedFileProcessing = onRequest(async (req, res) => {
  // Always set CORS headers
  res.set(corsHeaders);

  // Handle preflight request
  if (req.method === "OPTIONS") {
    return res.status(204).send("");
  }
  
  // Function logic continues...
});

调用函数的前端代码

async function uploadFile(event: React.FormEvent) {
  event.preventDefault();

  if (!theFile) return;

  setIsUploadingFile(true);

  const reader = new FileReader();
  reader.onload = async (e) => {
    if (!e.target?.result) return;

    const fileContent = JSON.parse(e.target.result as string);

    if (fileContent.features && Array.isArray(fileContent.features)) {
      const cloudFunctionURL = "https://uploadedfileprocessing-6d4acez4sq-uc.a.run.app?fileURL=";
      const groupedFeatures : any = {};
      for (const feature of fileContent.features) {
        const parentId = feature.properties.parent_id || 'unknown';
        if (!groupedFeatures[parentId]) {
          groupedFeatures[parentId] = [];
        }
        groupedFeatures[parentId].push(feature);
      }
      
      let numberOfCreated = 0;
      
      for (const [parentId, featuresGroup] of Object.entries(groupedFeatures)) {
        const groupedGeoJSON = {
          ...fileContent,
          features: featuresGroup
        };
      
        const fileName = `${parentId}__lvl3.json`;
        const fileBlob = new Blob([JSON.stringify(groupedGeoJSON)], { type: "application/json" });
        const storageRef = ref(storage, `geojsons/lvl3/${fileName}`);
        
        await uploadBytes(storageRef, fileBlob);
      
        const fileURL = `https://storage.googleapis.com/anwani-3b514/geojsons/lvl3/${encodeURIComponent(fileName)}`;
        await fetch(`${cloudFunctionURL}${fileURL}`);
      
        console.log(`Uploaded and triggered processing for ${fileName}`);
        numberOfCreated += 1;
      }
      for (const feature of fileContent.features) {
        const objectId = feature.properties.OBJECTID;
        const singleFileName = `${objectId}_single__lvl3.json`;
        const singleFeatureContent = {
          type: "FeatureCollection",
          features: [feature],
        };

        const singleFileBlob = new Blob([JSON.stringify(singleFeatureContent)], { type: "application/json" });
        const singleStorageRef = ref(storage, `geojsons/lvl3/${singleFileName}`);
        await uploadBytes(singleStorageRef, singleFileBlob);

        const singleFileURL = `https://storage.googleapis.com/anwani-3b514/geojsons/lvl3/${encodeURIComponent(singleFileName)}`;
        await fetch(`${cloudFunctionURL}${singleFileURL}`);

        console.log(`Uploaded and triggered processing for ${singleFileName}`);
      }

      setIsUploadingFile(false);
    } else {
      console.error("Invalid GeoJSON file format.");
      setIsUploadingFile(false);
    }
  };

  reader.readAsText(theFile);
}

预期效果

函数应正常运行并处理文件,无CORS问题。

已尝试操作

  • 设置了CORS头(但配置可能不正确)。

需要帮助的内容

  • 为何设置头后仍出现CORS错误?
  • 如何为部署在Google Cloud Run上的Firebase云函数正确配置CORS策略?

问题原因分析

  1. corsHeaders未明确定义:代码中调用res.set(corsHeaders)但未给出具体字段,若缺少Access-Control-Allow-Origin等必要项,等于未配置有效CORS头。
  2. Cloud Run额外配置缺失:部署在Cloud Run的函数,仅代码设置头可能不够,需在Cloud Run服务层面配置CORS,避免响应头被代理或负载均衡覆盖。
  3. 预请求处理不完整:虽处理了OPTIONS请求,但corsHeaders若缺少Access-Control-Allow-Methods、Access-Control-Allow-Headers等字段,预请求仍会失败。

正确配置方案

1. 完善代码中的CORS头配置

明确定义corsHeaders,指定允许的源、方法和头:

// 生产环境建议指定具体域名,而非通配符*
const corsHeaders = {
  "Access-Control-Allow-Origin": "https://admin-dashboard.3nwani.com",
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type",
  "Access-Control-Max-Age": "3600"
};

exports.uploadedFileProcessing = onRequest(async (req, res) => {
  res.set(corsHeaders);

  if (req.method === "OPTIONS") {
    return res.status(204).send("");
  }
  
  // 剩余业务逻辑...
});

若需允许多个域名,可根据请求Origin头动态判断:

const allowedOrigins = ["https://admin-dashboard.3nwani.com"];

exports.uploadedFileProcessing = onRequest(async (req, res) => {
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
    res.set("Access-Control-Allow-Origin", origin);
  }
  res.set({
    "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type",
    "Access-Control-Max-Age": "3600"
  });

  if (req.method === "OPTIONS") {
    return res.status(204).send("");
  }
  
  // 剩余业务逻辑...
});

2. 配置Cloud Run服务的CORS策略

若代码配置后仍报错,需在Cloud Run控制台补充配置:

  • 打开Google Cloud控制台,找到目标Cloud Run服务
  • 进入「编辑并部署新版本」→「容器」→「连接设置」
  • 展开「跨域资源共享(CORS)」,添加允许的源、方法和头
  • 保存并重新部署服务

3. 检查前端请求配置

确保前端fetch请求符合要求,比如POST请求需设置正确的Content-Type:

await fetch(`${cloudFunctionURL}${fileURL}`, {
  method: 'GET', // 或对应请求方法
  headers: {
    'Content-Type': 'application/json'
  }
});

验证方法

部署修改后,用浏览器开发者工具「网络」面板检查:

  • OPTIONS预请求的响应头是否包含正确的Access-Control-Allow-Origin
  • 实际请求的响应头是否同步包含该字段

内容的提问来源于stack exchange,提问作者Ahmed Wagdi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 22:00:15