Next.js API路由无法处理跨域POST请求的问题及解决
我需要在NextJS应用中处理来自其他域名的POST请求,于是在/pages/api目录下创建了receptor.ts文件,代码如下:
import { NextApiRequest, NextApiResponse } from 'next'; export default function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === 'POST') { console.log('POST') const message = req.body.message; console.log(`Message: ${message}`); res.status(200).json({ message: "Ok" }); } else { res.status(405).json({ error: "Not allowed" }); } res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST'); }
在另一应用中调用该接口的代码如下:
const url = `http://localhost:3000/api/receptor`; const data = { message: "Hello" }; fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));
报错信息
浏览器控制台报错:
Access to fetch at 'http://localhost:3000/api/receptor' from origin 'http://localhost:3001' 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.
IDE控制台报错:
error - Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
即使在请求中添加mode: "no-cors",仍会出现相同错误。
修正后的解决方案
import { NextApiRequest, NextApiResponse } from 'next'; export default function handler(req: NextApiRequest, res: NextApiResponse) { res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'POST'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.status(200).end(); return; } if (req.method === 'POST') { console.log('POST') const message = req.body.message; console.log(`Message: ${message}`); res.status(200).json({ message: "Ok" }); } else { res.status(405).json({ error: "Not allowed" }); } }
问题原因
未正确处理浏览器发送的预检请求(preflight request),同时原代码中存在在发送响应后再设置响应头的错误,导致ERR_HTTP_HEADERS_SENT报错。修正后的代码先设置CORS响应头,然后处理OPTIONS预检请求,再处理POST请求,解决了跨域问题和响应头错误。
内容的提问来源于stack exchange,提问作者assembler

