在 Next.Js 的 useEffect 中进行网络调用时出现 CORS 错误

Posted

技术标签:

【中文标题】在 Next.Js 的 useEffect 中进行网络调用时出现 CORS 错误【英文标题】:CORS error when making network call in useEffect in Next.Js 【发布时间】:2021-08-27 13:13:04 【问题描述】:

getStaticProps 中对 superhero.com 的 API 进行网络调用,但当我尝试在 useEffect 中进行相同操作时,它会引发 CORS 错误。

CORS 策略已阻止从源“http://localhost:3000”获取“https://superheroapi.com/api//1”的访问权限:没有“Access-Control-Allow-Origin”标头存在于请求的资源上。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

我曾尝试使用 fetch 以及 axios 进行网络调用,但遇到了同样的错误。 Next.js 是否存在问题或限制?

编辑:尝试在useEffect 中使用 JSON 占位符 API,它正在工作。

【问题讨论】:

这能回答你的问题吗? How does Access-Control-Allow-Origin header work? 这是一个非常合理的错误,与 Next.js 无关,我没有想到会发生这种情况,一时冲动就贴在这里。答案中的@engineforce 非常简洁地解释了它。 【参考方案1】:

CORS

当您尝试从另一个域的一个域访问资源时,会发生 CORS 错误。它只发生在浏览器中,是一项安全功能。

所以本质上,当您在localhost:3000 上从https://superheroapi.com/api/1 获取数据时,浏览器首先会询问superheroapi.com,“嘿,这个域可以从你那里获取数据吗?”。 superheroapi.com 然后会说,“我只接受来自这些域的请求”。如果localhost:3000 不在该列表中,您将收到 CORS 错误。

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

您可以通过Access-Control-Allow-Origin 标头更改superheroapi.com 接受的域。您可以手动完成,或者有一个方便的 npm 包可以在 Next.js 中为您处理。

修复 Next.js 中的 CORS

默认情况下,在 Next.js 中,CORS 标头仅限于同域流量。但是,您可以更改此设置。

Next.js 实际上在他们的文档中有一个关于向 api 路由添加 CORS 标头的指南。

https://nextjs.org/docs/api-routes/api-middlewares#connectexpress-middleware-support

不过,简而言之,首先安装 CORS 包。

npm i cors
# or
yarn add cors
# or
pnpm add cors

然后将其添加到 API 路由中。

import Cors from 'cors'

// Initializing the cors middleware
const cors = Cors(
  methods: ['GET', 'HEAD'],
)

// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(req, res, fn) 
  return new Promise((resolve, reject) => 
    fn(req, res, (result) => 
      if (result instanceof Error) 
        return reject(result)
      

      return resolve(result)
    )
  )


async function handler(req, res) 
  // Run the middleware
  await runMiddleware(req, res, cors)

  // Rest of the API logic
  res.json( message: 'Hello Everyone!' )


export default handler

代码 sn-ps 取自 Next.js 文档。所有功劳都归功于 Next.js 的制作者。

【讨论】:

我试过了,当我从同一个 Next App 发出 POST 请求时,它通过了。由于方法中不允许 POST 请求,它不应该抛出错误吗?【参考方案2】:

useEffect 中的代码在前端/浏览器中运行,因此必须遵守 CORS。 getStaticProps 在构建时运行,因此没有 CORS 限制。

如果 superheroapi.com API 在您的控制之下,您应该添加 CORS 响应标头来解决问题。否则需要创建反向代理,例如https://www.npmjs.com/package/cors-anywhere

【讨论】:

请查看编辑。解决 CORS 错误的解决方案是什么?【参考方案3】:

您必须在经过验证的域上运行您的代码。 一些 api 给你 localhost 请求的 cors 错误。

简单的方法是:尝试定义一个本地域(在主机文件中将该域的本地 dns 更改为 127.0.0.1)并像这样编写一个 server.js 文件。 将“next.yourdomain.com”替换为您的域;)

const  createServer,  = require('http');
const  parse,  = require('url');
const next = require('next');

// const dev = process.env.NODE_ENV !== 'production';
const dev = false;
const app = next(dev, );
const handle = app.getRequestHandler();
const HOST = 'next.yourdomain.com';
const PORT = 8090;

app.prepare().then(() => 
  createServer((req, res) => 
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  ).listen(PORT, HOST, (err) => 
    if (err) throw err;
    console.log(`Starting Next.js at http://$HOST:$PORT`);
  );
);

然后运行

next build && node server.js

您还必须在最终部署时丢弃此文件。

【讨论】:

以上是关于在 Next.Js 的 useEffect 中进行网络调用时出现 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

Next js 应用刷新时,useEffect 不调度 redux saga 动作并更新状态

如何在头组件中使用效果(ReactJS/Next.js)

Next.js:如何从元素中获取应用样式?

Next.js 重定向/验证

在 useEffect 内部或外部定义函数?

Next.JS Redux 调度在 getStaticProps() 中不起作用