在 next.js 中调用 API 并避免 CORS 错误的最佳实践

问题描述 投票:0回答:3

我正处于设置 next.js 应用程序的早期阶段,到目前为止我只有使用 React 的经验。

我在 localhost:3000 上设置了一个前端应用程序 (next.js),在 localhost:5000 上设置了一个后端应用程序 (node.js/express)。他们都工作。

现在我尝试从前端调用快速端点,我正在做的是:

const registerUser = async event => {
        event.preventDefault()
        
        const res = await fetch(
            process.env.NEXT_PUBLIC_SERVER + '/user/signup',
            {
                body: JSON.stringify({
                    username: event.target.name.value,
                    email: event.target.email.value,
                    password: event.target.password.value
                }),
                headers: {
                    'Content-Type': 'application/json'
                },
                method: 'POST'
            }
        )

        result = await res.json()
    }

我收到一条错误消息

Access to fetch at 'http://localhost:5000/user/signup' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

请注意:端点使用 Postman 按预期工作。

我做了一些研究,发现一些资源说我应该调用内部 next.js 端点(pages/api),然后从那里调用我的 api。这是 next.js 的最佳实践吗?在react中我只是用来直接调用api。

除了如何解决这个问题之外,我想知道这种情况下的最佳做法是什么?谢谢。

node.js reactjs express next.js cors
3个回答
6
投票

如果您有单独的前端和后端服务器(例如,next.js 和express),并且无法侦听同一端口,则有两种广泛的替代方案:

浏览器从一台服务器加载前端并向另一台服务器发出 API 请求

next.js <-- browser --> express

这需要后端应用程序设置 CORS 标头,例如使用

cors
和语句

app.use(cors({origin: "host of next.js", ...}));

或者浏览器向 next.js 的端口发出所有请求,这会将所有 API 请求转发到其他服务器

browser --> next.js --> express

在这种情况下不需要 CORS,但 API 请求比以前需要更多的跃点。所以这是简单性与性能的比较(就像经常发生的那样)。


2
投票

首先,您确定需要 Express BE 吗? Next.js 的强大之处在于其无服务器方法,大多数时候,除非您有非常复杂的 BE,否则您可以使用无服务器功能完成所有操作。

如果您确实需要为 Next 应用程序提供单独的 Express 服务器,请记住您将失去一些重要的 Next 功能:

在决定使用自定义服务器之前,请记住,只有当 Next.js 的集成路由器无法满足您的应用程序要求时才应使用它。自定义服务器将删除重要的性能优化,例如无服务器功能和自动静态优化。

通常为了解决开发环境中的 CORS 问题,因为您需要 FE 运行在与 BE 不同的 PORT 上才能进行热重载,当您使用 React 时,最好的方法是代理方法,您只需在 package.json 中添加一个条目即可在 React 项目上,

   "proxy": "http://localhost:5000" (if your server runs on PORT 5000)

来源:https://create-react-app.dev/docs/proxying-api-requests-in-development/

这样,所有 http 流量都将在端口 5000 上重定向,并到达您的 Express 服务器,同时保持热重载功能和您的客户端文件在端口 3000 上运行。

顺便说一句,如果您有一个标准的 React FE 和一个自定义的 Express BE,就是这种情况,如果您使用 NextJS,即使有一个自定义的 Express 服务器,您也需要创建服务器并使用 Next 连接它:

    / server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  createServer(async (req, res) => {
    try {
      // 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)
      const { pathname, query } = parsedUrl

      if (pathname === '/a') {
        await app.render(req, res, '/a', query)
      } else if (pathname === '/b') {
        await app.render(req, res, '/b', query)
      } else {
        await handle(req, res, parsedUrl)
      }
    } catch (err) {
      console.error('Error occurred handling', req.url, err)
      res.statusCode = 500
      res.end('internal server error')
    }
  }).listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://${hostname}:${port}`)
  })
})

来源:https://nextjs.org/docs/advanced-features/custom-server

再次建议您深入评估您的应用是否真的需要自定义 Express 服务器,因为大多数时候您不需要,并且在无服务器环境中开发体验会更加流畅!


0
投票

我刚刚花了几个小时调试这个问题。 就我而言,后端服务器正在运行 FastAPI。 最初的症状是 CORS 错误,但当我深入研究它时,我发现这实际上是对尾部斜杠的严重分歧。 默认情况下,NextJS 会发出 308 永久重定向,以从传入请求中删除任何尾部斜杠。 但很容易无意中将 FastAPI 端点配置为需要斜杠,例如:

router = APIRouter(prefix="/frobs", ...)
@router.post("/", ...)

收到发送到

/frobs
的 POST 后,默认情况下,FastAPI 会发出 307 临时重定向,以将 NextJS 删除的斜杠放回去。 我收到 CORS 错误,因为这个 307 有一个绝对 URL,其
host:port
当然与前端服务器的不同。 其他(甚至)不太幸运的灵魂可能会得到重定向循环。

有几种不同的方法可以修复它:

  1. 删除端点处的斜线:
    @router.post("", ...)
    。 这就是我所做的,并且有效。
  2. 更改 NextJS 中的尾部斜杠配置。 当然,只有当您的 FastAPI 端点都被编写为需要斜杠时,这才有效。 对您的路线进行
  3. 几种不同的黑客
  4. 之一,以便您的所有路线都可以在有斜线和没有斜线的情况下工作。 使用
  5. 这个 FastAPI mod
  6. (当您阅读本文时,它可能已经被合并)。
  7. 对于 (1) 或 (2),您可能还应该在
redirect_slashes=False

构造函数调用中传递

FastAPI
。 这可以防止发出任何重定向(在反向代理情况下这些重定向永远不会正确,因为它们包含绝对 URL);您会收到 404。
    

© www.soinside.com 2019 - 2024. All rights reserved.