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

部署在Vercel的前端调用同平台后端API时出现CORS错误

部署在Vercel的API遭遇CORS错误排查

我调用Vercel上部署的API时出现CORS错误:

  • Insomnia可正常获取数据
  • 本地运行的网站副本能正常调用API
  • 网站上线后使用相同链接触发CORS错误

前端基于React开发,用Axios发起请求,网站同样托管在Vercel。浏览器开发者工具显示strict-origin-when-cross-origin。

浏览器控制台网络面板截图

API的vercel.json配置

{
  "version": 2,
  "builds": [
    {
      "src": "index.js",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/api/(.*)",
      "methods": ["GET", "OPTIONS", "PATCH", "DELETE", "POST", "PUT"],
      "headers": {
        "Access-Control-Allow-Credentials": "true",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "GET,OPTIONS,PATCH,DELETE,POST,PUT",
        "Access-Control-Allow-Headers": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
      },
      "dest": "/index.js"
    },
    {
      "src": "/(.*)",
      "dest": "/index.js"
    }
  ]
}

网站的vercel.json配置

{
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Credentials", "value": "true" },
        { "key": "Access-Control-Allow-Origin", "value": "*" },
        { "key": "Access-Control-Allow-Methods", "value": "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
        { "key": "Access-Control-Allow-Headers", "value": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" }
      ]
    }
  ],
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/index.html"
    }
  ]
}

后端API代码

const express = require("express");
const { MongoClient } = require("mongodb");
require("dotenv").config();
const axios = require("axios");

const app = express();
const port = process.env.PORT || 3000;

const allowCors = (fn) => async (req, res) => {
  res.setHeader("Access-Control-Allow-Credentials", true);
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET,OPTIONS,PATCH,DELETE,POST,PUT"
  );
  res.setHeader(
    "Access-Control-Allow-Headers",
    "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
  );

  if (req.method === "OPTIONS") {
    res.status(200).end();
    return;
  }

  return await fn(req, res);
};

const uri = process.env.MONGO_URI;

app.use(express.json());

app.get(
  "/api/chapters",
  allowCors(async (req, res) => {
    const client = new MongoClient(uri);

    try {
      await client.connect();
      const database = client.db("manhwa"); 
      const collection = database.collection("chapters"); 

      const chapters = await collection.find({}).toArray();

      if (chapters.length === 0) {
        throw new Error("No chapters found in the collection.");
      }

      res.status(200).json(chapters);
    } catch (e) {
      console.error("Error fetching chapters:", e.message);
      res
        .status(500)
        .json({ error: "Failed to fetch data", details: e.message });
    } finally {
      await client.close();
    }
  })
);

app.get(
  "/",
  allowCors(async (req, res) => {
    res.send("You Shoulden't Be Here.");
  })
);

app.get(
  "/api/chapters/:chapter_id",
  allowCors(async (req, res) => {
    const client = new MongoClient(uri);

    try {
      await client.connect();
      const database = client.db("manhwa");
      const collection = database.collection("chapterDetails");

      const chapter_id = req.params.chapter_id;
      const chapter = await collection.findOne({ chapter_id: chapter_id });

      if (!chapter) {
        res.status(404).json({ error: "Chapter not found" });
      } else {
        res.status(200).json(chapter);
      }
    } catch (e) {
      console.error("Error fetching chapter:", e.message);
      res
        .status(500)
        .json({ error: "Failed to fetch data", details: e.message });
    } finally {
      await client.close();
    }
  })
);

app.get(
  "/api/proxy",
  allowCors(async (req, res) => {
    const { url } = req.query;

    if (!url) {
      return res.status(400).json({ error: "No URL provided" });
    }

    try {
      const response = await axios.get(url, { responseType: "arraybuffer" });

      res.setHeader("Access-Control-Allow-Origin", "*");
      res.setHeader(
        "Access-Control-Allow-Methods",
        "GET,OPTIONS,PATCH,DELETE,POST,PUT"
      );
      res.setHeader(
        "Access-Control-Allow-Headers",
        "X-Requested-With, Content-Type, Authorization"
      );

      res.end(response.data);
    } catch (error) {
      console.error("Error in proxy endpoint:", error);
      res
        .status(500)
        .json({ error: "Error fetching the URL", details: error.message });
    }
  })
);

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});

我已经在API和vercel.json中配置了CORS相关规则,但问题仍未解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 17:44:57