为何仅在onChange触发GET请求时出现CORS错误?
你遇到的这个CORS问题,核心原因是两种调用场景下,axios发送的请求携带的HTTP头不一样:
对比成功和失败的请求头可以看到,失败的请求在预检(OPTIONS)阶段多了Access-Control-Request-Headers: authorization这个字段——这说明浏览器告诉HERE的API服务器:我接下来的GET请求要带Authorization头,但HERE的API服务器不允许自定义Authorization头,直接返回了405状态码,导致预检失败,最终触发CORS拦截。
那为什么单独调用函数时没问题,在onChange里调用就会带Authorization头?大概率是你的项目里全局配置了axios请求拦截器,会自动给请求添加Authorization头(比如从localStorage取token,用来验证后端API)。而单独调用的时机(比如组件初始化渲染时),这个拦截器还没生效(比如token还没被存入localStorage),所以请求不带额外头;当用户在输入框输入触发onChange时,拦截器已经生效,axios自动给HERE的API请求加上了Authorization头,才引发了CORS问题。
下面提供三种可行的解决思路,你可以根据自己的项目情况选择:
1. 给HERE的请求单独禁用Authorization头
直接在调用HERE API的axios请求里,显式覆盖Authorization头为undefined,这样就不会触发带该头的预检请求:
export const autoCompleteFullAddress = async query => { let address = null; try { const response = await axios.get('https://autocomplete.geocoder.api.here.com/6.2/suggest.json', { params: { app_id: hereKeys.appId, app_code: hereKeys.appCode, query: query, maxresults: 1, }, // 关键:覆盖全局的Authorization头 headers: { Authorization: undefined } }); address = response.data.suggestions[0].address; } finally { return address; } };
2. 修改全局axios拦截器,跳过第三方API的Authorization添加
如果你的全局拦截器是用来给自己的Node.js后端API加token的,可以给第三方API请求加一个自定义标记,让拦截器跳过添加Authorization头:
首先修改请求配置,添加自定义标记:
export const autoCompleteFullAddress = async query => { let address = null; try { const response = await axios.get('https://autocomplete.geocoder.api.here.com/6.2/suggest.json', { params: { ... }, // 自定义标记,告诉拦截器跳过Authorization skipAuthorization: true }); address = response.data.suggestions[0].address; } finally { return address; } };
然后修改全局axios拦截器:
axios.interceptors.request.use(config => { // 只有没有skipAuthorization标记的请求,才添加Authorization头 if (!config.skipAuthorization) { const token = localStorage.getItem('token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } } return config; });
3. 通过自己的Node.js服务器转发请求
既然你已经配置了Create React App的proxy指向localhost:5000,可以在Node.js后端写一个转发路由,让前端请求自己的服务器,再由服务器转发到HERE的API——这样就绕开了浏览器的CORS限制:
后端(Node.js)添加路由:
const express = require('express'); const axios = require('axios'); const router = express.Router(); const hereKeys = require('./path/to/hereConfig'); // 转发HERE autocomplete请求 router.get('/api/here-autocomplete', async (req, res) => { try { const { query, maxresults = 1 } = req.query; const response = await axios.get('https://autocomplete.geocoder.api.here.com/6.2/suggest.json', { params: { app_id: hereKeys.appId, app_code: hereKeys.appCode, query, maxresults } }); res.json(response.data); } catch (error) { res.status(error.response?.status || 500).json(error.response?.data || { message: '请求失败' }); } }); module.exports = router;
前端修改请求地址:
export const autoCompleteFullAddress = async query => { let address = null; try { const response = await axios.get('/api/here-autocomplete', { params: { query: query, maxresults: 1, } }); address = response.data.suggestions[0].address; } finally { return address; } };
内容的提问来源于stack exchange,提问作者Matt Weber

