NodeJS调用第三方API无CORS错误,React/JS调用却报错求助
我在NodeJS环境中调用第三方API时完全正常,没有CORS错误;但用React/原生JavaScript通过fetch调用同一个API时,却被CORS政策拦截,提示响应缺少Access-Control-Allow-Origin头。想知道是不是JS请求里漏了请求头或者语法有问题?
NodeJS 代码
const express = require('express'); const port = 3000; const router = express(); router.get('/', (req, res) => { res.send('Hi'); }) var request = require('request'); var options = { 'method': 'GET', 'url': 'URL', 'headers': { 'Authorization': 'API_KEY' } }; request(options, function (error, response) { if (error) throw new Error(error); console.log(response.body); }); router.listen(port, function(err) { if(err) return; console.log('Server Up'); })
JavaScript 代码
const options = { method: 'GET', headers: { 'Authorization': 'API_KEY' } }; fetch('URL', options) .then(response => response.json()) .then(response => console.log(response)) .catch(err => console.error(err));
错误信息
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.
注:调用的GET请求API并非自有API。
原因与解决办法
核心原因
你的JS请求语法和请求头没有问题,问题出在浏览器的CORS安全机制:
- NodeJS是服务器端请求,直接和第三方API通信,不受浏览器的CORS政策限制;
- 浏览器发起的跨域请求(前端域名和第三方API域名不同)会自动触发CORS校验,要求第三方API返回
Access-Control-Allow-Origin响应头,而这个第三方API没有配置该头,所以被拦截。
解决办法
1. 用自己的NodeJS服务做代理(推荐)
让前端请求自己的Express服务,再由服务端转发到第三方API,这样前端请求的是同域名接口,不会触发CORS。修改你的Express代码:
const express = require('express'); const port = 3000; const request = require('request'); const app = express(); // 新增代理接口 app.get('/api/proxy', (req, res) => { const thirdPartyUrl = '第三方API的实际URL'; const options = { method: 'GET', url: thirdPartyUrl, headers: { 'Authorization': 'API_KEY' } }; // 转发请求到第三方API request(options, (error, response) => { if (error) { res.status(500).send('请求第三方API失败:' + error.message); return; } // 将第三方API的响应返回给前端 res.setHeader('Content-Type', response.headers['content-type']); res.send(response.body); }); }); app.get('/', (req, res) => { res.send('Hi'); }) app.listen(port, (err) => { if (err) return console.error(err); console.log(`Server running on port ${port}`); })
前端代码修改为请求代理接口:
fetch('/api/proxy') .then(response => response.json()) .then(data => console.log(data)) .catch(err => console.error(err));
2. 使用no-cors模式(仅限无需读取响应的场景)
如果只需要发送请求,不需要获取响应内容,可以设置mode: 'no-cors',但这种模式下无法读取返回的响应数据:
const options = { method: 'GET', mode: 'no-cors', headers: { 'Authorization': 'API_KEY' } }; fetch('第三方API的URL', options) .then(response => console.log('请求已发送,但无法读取响应')) .catch(err => console.error(err));
3. 联系第三方API提供者添加跨域配置
如果能联系到第三方API的维护方,可以请求他们在响应头中添加Access-Control-Allow-Origin,允许你的前端域名(例如https://your-frontend-domain.com)或者所有域名(*)访问。
内容的提问来源于stack exchange,提问作者Bhartesh Kaushik

