同域下React+Node文件下载时出现CORS错误求助
问题描述
后端服务器域名是https://example.com:3000,React应用由Apache托管在https://example.com,其他API接口都能正常响应,但从服务器下载文件时出现CORS错误,具体错误提示:
Access to fetch at 'https://example.com:3000/uploads/private-79-38/1676275634939-chats.pdf' from origin 'http://localhost:3000' has been blocked by CORS policy: 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.
相关代码
React前端代码
<Link to="#" className="text-decoration-none"> <button className="dropdown-item " type="button" onClick={() => { console.log("called"); let headers = new Headers(); headers.append("Content-Type", "application/json"); headers.append("Accept", "application/json"); fetch(file.file_path, { headers: headers, }) .then((res) => { console.log(res); return res.blob(); }) .then((blob) => { console.log(blob); const href = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.download = file.file_real_name; a.href = href; a.click(); a.href = ""; }); }} > Download </button> </Link>;
Node.js后端代码
app.use(cors());
错误截图

解决方法
1. 确保静态文件请求经过CORS中间件
你的cors()中间件可能只处理了API路由,而uploads目录下的静态文件直接由静态文件服务处理,没经过CORS配置。调整后端代码顺序,先挂载CORS再配置静态文件:
const express = require('express'); const cors = require('cors'); const app = express(); // 先加载CORS中间件,让所有请求都经过它 app.use(cors()); // 再配置静态文件服务,确保uploads下的文件请求也带上CORS头 app.use('/uploads', express.static('uploads'));
2. 移除不必要的请求头
你在fetch里设置的Content-Type: application/json和Accept: application/json不适合下载PDF文件,会触发浏览器的预检OPTIONS请求,而静态文件服务可能没处理这类请求。简化fetch代码:
<Link to="#" className="text-decoration-none"> <button className="dropdown-item " type="button" onClick={() => { fetch(file.file_path) .then((res) => res.blob()) .then((blob) => { const href = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.download = file.file_real_name; a.href = href; a.click(); // 释放URL对象资源,避免内存泄漏 window.URL.revokeObjectURL(href); }); }} > Download </button> </Link>;
3. 明确指定允许的跨域来源
开发环境用http://localhost:3000,生产环境用https://example.com,可以针对性配置CORS:
// 开发环境允许localhost,生产环境允许example.com const allowedOrigins = ['http://localhost:3000', 'https://example.com']; app.use(cors({ origin: (origin, callback) => { if (!origin || allowedOrigins.includes(origin)) { callback(null, true); } else { callback(new Error('Not allowed by CORS')); } } }));
4. 用反向代理彻底规避跨域
如果后端和前端同域名,可以在Apache配置反向代理,把https://example.com/uploads的请求转发到https://example.com:3000/uploads,这样前端直接请求同域名路径,彻底解决CORS问题。示例Apache配置:
ProxyPass /uploads https://example.com:3000/uploads ProxyPassReverse /uploads https://example.com:3000/uploads
内容的提问来源于stack exchange,提问作者pankaj

