部署后登录接口遇CORS拦截及ERR_HTTP_HEADERS_SENT错误求助
部署人脸识别项目后登录接口遭遇CORS拦截及服务器报错问题
问题描述
我是JavaScript新手,近期部署了人脸识别项目,开发环境下一切正常,但部署后登录时遭遇CORS拦截(注册功能可正常使用,数据库已确认连接正常)。
CORS配置及登录接口代码
app.use(cors({ origin:["https://almoghasson.github.io/Face-Recognition/","http://localhost:3001"], allowedHeaders: ['Content-Type', 'Authorization'], credentials: true, })); app.post('/signin', (req, res) => { const { email, psw } = req.body const user = { email: email } // postgres.select('email', 'hash').from('login') .where('email', '=', email) .then(data => { const isValid = bcrypt.compareSync(psw, data[0].hash) if (isValid) { const refreshToken = uuid(); // store token in db & cookie postgres.select('*').from('users') .where('email', '=', email) .update({ token: refreshToken }) .catch(err => res.status(400).json(err)) //return user data return postgres.select('*').from('users') .where('email', '=', email) .then(user => { const { token: _, ...userWithoutRefreshToken } = user[0]; const accessToken = generateAccessToken(userWithoutRefreshToken); res.cookie(REFRESH_TOKEN_COOKIE_NAME, refreshToken, { httpOnly: false, maxAge: 24 * 60 * 60 * 1000, sameSite: "none", path: '/', secure: true }); res.json({ accessToken }); }) .catch(err => res.status(400).json('unable to get user')) } else { res.status(400).json('wrong credentials') } }) .catch(err => res.status(400).json('wrong credentials')) });
前端Fetch代码
fetch('https://face-recognition-api-n3yg.onrender.com/signin', { method:'post', headers : { 'Content-Type':'application/json', }, body: JSON.stringify({ email: this.state.signInEmail, psw: this.state.signInPsw }), credentials: 'include' }) .then(res => res.json()) .then(res => { if (res.accessToken){ const user = decodeAndStoreJWT(res.accessToken); this.props.setBearer(res.accessToken) this.props.loadUser(user) this.props.onRouteChange('home') this.props.runInterval() } })
疑惑点
- 配置的origin未被接受,原因是什么?
- 页面URL为
.../face-recognition/,但实际请求的origin仅为...github.io,这是为什么?
已尝试的解决方案
- 在前端代码中添加
access-allow-origin请求头,无效 - 将CORS的origin设为
"*",无效,且该方案不推荐
服务器控制台错误日志
Nov 1 06:41:45 PM Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client Nov 1 06:41:45 PM at new NodeError (node:internal/errors:372:5) Nov 1 06:41:45 PM at ServerResponse.setHeader (node:_http_outgoing:576:11) Nov 1 06:41:45 PM at ServerResponse.header (/opt/render/project/src/Backend/node_modules/express/lib/response.js:794:10) Nov 1 06:41:45 PM at ServerResponse.send (/opt/render/project/src/Backend/node_modules/express/lib/response.js:174:12) Nov 1 06:41:45 PM at ServerResponse.json (/opt/render/project/src/Backend/node_modules/express/lib/response.js:278:15) Nov 1 06:41:45 PM at /opt/render/project/src/Backend/server.js:86:45 Nov 1 06:41:45 PM at processTicksAndRejections (node:internal/process/task_queues:96:5) { Nov 1 06:41:45 PM code: 'ERR_HTTP_HEADERS_SENT' Nov 1 06:41:45 PM }
问题分析与解决
1. Origin配置不生效的核心原因
- Origin匹配规则错误:浏览器发送的Origin仅包含协议、域名、端口,不包含URL路径。你配置的
https://almoghasson.github.io/Face-Recognition/带了路径,无法匹配实际请求的https://almoghasson.github.io,导致CORS拦截。 - 服务器重复响应报错:登录接口中,
update操作的catch会提前返回错误响应,后续代码仍会执行并再次发送响应,触发ERR_HTTP_HEADERS_SENT错误,导致浏览器无法正确解析CORS响应头,进一步加剧拦截问题。
2. 页面URL带路径但Origin是根域名的原因
浏览器的Origin定义是协议+域名+端口,不管页面在域名下的哪个子路径,请求的Origin都是根域名,这是浏览器的标准安全行为。
3. 具体修复步骤
修复CORS配置
将origin数组中的带路径项改为根域名:
app.use(cors({ origin:["https://almoghasson.github.io","http://localhost:3001"], allowedHeaders: ['Content-Type', 'Authorization'], credentials: true, }));
修复登录接口的重复响应问题
把update和select改为链式调用,避免并行执行导致的多次响应:
app.post('/signin', (req, res) => { const { email, psw } = req.body postgres.select('email', 'hash').from('login') .where('email', '=', email) .then(data => { const isValid = bcrypt.compareSync(psw, data[0].hash) if (isValid) { const refreshToken = uuid(); // 先执行更新操作,完成后再查询用户数据 return postgres.select('*').from('users') .where('email', '=', email) .update({ token: refreshToken }) .then(() => postgres.select('*').from('users').where('email', '=', email)) .then(user => { const { token: _, ...userWithoutRefreshToken } = user[0]; const accessToken = generateAccessToken(userWithoutRefreshToken); res.cookie(REFRESH_TOKEN_COOKIE_NAME, refreshToken, { httpOnly: false, maxAge: 24 * 60 * 60 * 1000, sameSite: "none", path: '/', secure: true }); res.json({ accessToken }); }) .catch(err => res.status(400).json(err)) } else { res.status(400).json('wrong credentials') } }) .catch(err => res.status(400).json('wrong credentials')) });
4. 额外注意事项
- 前端不要手动设置
access-allow-origin请求头,该头是服务器返回的响应头,前端设置无效。 - 当
credentials: true时,origin不能设为*,这是浏览器的安全限制,所以之前设*无效是正常的。
内容的提问来源于stack exchange,提问作者Almog Hasson
相关产品推荐
相关产品推荐

