React应用调用Firebase云函数时无法解决CORS错误
解决React + Google Cloud Functions的CORS上传错误
问题背景
已花费3小时尝试解决CORS错误,试过部署网站、修改代理、调整React配置、更改CORS设置等方法,仍未解决。使用create-react-app开发前端,搭配Google Cloud Functions处理图片上传,请求始终触发CORS错误。
前端代码(React)
import './App.css'; import React from 'react'; import axios from 'axios'; function App() { const [file, setFile] = React.useState(null); function fileSelected(e) { setFile(()=> e.target.files[0]); } function uploadFile() { console.log(file) const fd = new FormData(); fd.append('image', file, file.name) axios.post('https://us-central1-athelasapp.cloudfunctions.net/uploadFile', fd) .then(res => { console.log(res) }); } return ( <div className="App"> <input type="file" onChange={fileSelected}/> <input type="submit" onClick={uploadFile}/> </div> ); } export default App;
Google Cloud Functions代码
const functions = require("firebase-functions"); const express = require("express"); const cors = require("cors"); const app = express(); const Busboy = require("busboy"); const os = require("os"); const path = require("path"); const fs = require("fs"); const gcconfig = { projectId: "athelasapp", keyFilename: "athelasapp-firebase-adminsdk-yojnp-1e9141a009.json", }; const {Storage} = require("@google-cloud/storage"); const gcs = new Storage(gcconfig); app.use(cors({origin: true})); exports.uploadFile = functions.https.onRequest(app); app.post("/", (req, res) =>{ if (req.method !== "POST") { return res.status(500).json({ message: "Method Does Not Work", }); } const busboy = new Busboy({headers: req.headers}); let uploadData = null; busboy.on("file", (fieldname, file, filename, encoding, mimetype) =>{ const filepath = path.joing(os.tmpdir(), filename); uploadData = {file: filepath, type: mimetype}; file.pipe(fs.createWriteStream(filepath)); }); busboy.on("finish", ()=>{ const bucket = gcs.bucket("athelasapp.appspot.com"); bucket.upload(uploadData.file, { uploadType: "media", metadata: { metadata: { contentType: uploadData.type, }, }, }); }).then(() => { res.status(200).json({ message: "Method Works!", }); }).catch((err) =>{ res.status(500).json({ message: "Method Failed!", }); }); busboy.end(req.rawBody); });
问题排查与解决方案
1. 修复后端拼写错误
Cloud Functions代码中path.joing是拼写错误,正确应为path.join。这个错误会导致服务器内部报错,无法返回正确响应,浏览器会将此类错误判定为CORS问题。
2. 修正Promise链绑定错误
busboy.on("finish")回调中,bucket.upload是异步操作,需返回该Promise才能让后续.then/.catch正确捕获结果:
busboy.on("finish", () => { const bucket = gcs.bucket("athelasapp.appspot.com"); // 返回upload的Promise,绑定后续处理逻辑 return bucket.upload(uploadData.file, { uploadType: "media", metadata: { metadata: { contentType: uploadData.type, }, }, }); }).then(() => { res.status(200).json({ message: "Method Works!", }); }).catch((err) => { console.error(err); // 打印错误日志便于排查 res.status(500).json({ message: "Method Failed!", error: err.message }); });
3. 优化CORS中间件配置
虽然已添加app.use(cors({origin: true})),可显式指定允许的域名避免泛匹配问题:
// 本地开发用http://localhost:3000,线上替换为实际部署域名 app.use(cors({origin: ["http://localhost:3000", "https://your-deployed-domain.com"]}));
4. 前端添加错误捕获
在axios请求中添加.catch,查看具体错误信息,而非仅依赖浏览器的CORS提示:
axios.post('https://us-central1-athelasapp.cloudfunctions.net/uploadFile', fd) .then(res => { console.log(res) }) .catch(err => { console.error("请求详情错误:", err); });
5. 配置Google Cloud Storage的CORS规则
若前端需直接访问上传后的文件,需为GCS桶设置CORS规则:
# 先创建cors-config.json文件 echo '[ { "origin": ["http://localhost:3000", "https://your-deployed-domain.com"], "method": ["GET", "POST", "PUT"], "responseHeader": ["Content-Type"], "maxAgeSeconds": 3600 } ]' > cors-config.json # 应用规则到桶 gcloud storage buckets update gs://athelasapp.appspot.com --cors-file cors-config.json
6. 重新部署Cloud Functions
修改代码后,重新部署函数生效:
firebase deploy --only functions:uploadFile
内容的提问来源于stack exchange,提问作者Bykaugan
相关产品推荐
相关产品推荐

