我正处于设置 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。
除了如何解决这个问题之外,我想知道这种情况下的最佳做法是什么?谢谢。
如果您有单独的前端和后端服务器(例如,next.js 和express),并且无法侦听同一端口,则有两种广泛的替代方案:
浏览器从一台服务器加载前端并向另一台服务器发出 API 请求
next.js <-- browser --> express
cors
和语句
app.use(cors({origin: "host of next.js", ...}));
或者浏览器向 next.js 的端口发出所有请求,这会将所有 API 请求转发到其他服务器
browser --> next.js --> express
在这种情况下不需要 CORS,但 API 请求比以前需要更多的跃点。所以这是简单性与性能的比较(就像经常发生的那样)。
首先,您确定需要 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 服务器,因为大多数时候您不需要,并且在无服务器环境中开发体验会更加流畅!
我刚刚花了几个小时调试这个问题。 就我而言,后端服务器正在运行 FastAPI。 最初的症状是 CORS 错误,但当我深入研究它时,我发现这实际上是对尾部斜杠的严重分歧。 默认情况下,NextJS 会发出 308 永久重定向,以从传入请求中删除任何尾部斜杠。 但很容易无意中将 FastAPI 端点配置为需要斜杠,例如:
router = APIRouter(prefix="/frobs", ...)
@router.post("/", ...)
收到发送到
/frobs
的 POST 后,默认情况下,FastAPI 会发出 307 临时重定向,以将 NextJS 删除的斜杠放回去。 我收到 CORS 错误,因为这个 307 有一个绝对 URL,其 host:port
当然与前端服务器的不同。 其他(甚至)不太幸运的灵魂可能会得到重定向循环。
有几种不同的方法可以修复它:
@router.post("", ...)
。 这就是我所做的,并且有效。redirect_slashes=False
构造函数调用中传递
FastAPI
。 这可以防止发出任何重定向(在反向代理情况下这些重定向永远不会正确,因为它们包含绝对 URL);您会收到 404。