使用Axios调用DVLA EPS API遇两类错误:CORS及axios不是函数
错误1:CORS跨域限制
Access to XMLHttpRequest at 'https://uat.driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles' from origin 'http://localhost:3000' 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.
原因
浏览器的同源策略禁止前端直接调用不同域名的API,DVLA的UAT环境API未配置允许http://localhost:3000作为跨域源,因此拦截了请求。另外,前端直接暴露API Key会有泄露风险,也不建议这么做。
解决方案
必须通过后端代理转发请求,这里提供两种简单方案:
- Create React App内置代理:在项目的
package.json中添加代理配置:
之后前端请求路径改为本地代理路径:"proxy": "https://uat.driver-vehicle-licensing.api.gov.uk"const api_url = "/vehicle-enquiry/v1/vehicles"; - 自定义后端服务:用Node.js/Express写一个简单接口,在后端中调用DVLA API,前端再请求自己的后端接口,这样既规避跨域问题,又能保护API Key。
错误2:Uncaught TypeError: axios is not a function
原因
你照搬的文档示例同时混用了ES模块的import和CommonJS的require,并且在函数作用域内重新声明axios,覆盖了全局导入的变量,导致axios变成模块对象而非可调用的函数。
解决方案
统一使用ES模块导入方式,删除重复的require声明:
修改后的文档示例代码:
import './App.css'; import axios from 'axios'; function App() { const data = { registrationNumber: 'AA19AAA' }; const config = { method: 'post', url: 'https://uat.driver-vehicle-licensing.api.gov.uk/vehicle-enquiry/v1/vehicles', headers: { 'x-api-key': 'API KEY HERE', 'Content-Type': 'application/json', }, data: data, }; axios(config) .then(response => { console.log(JSON.stringify(response.data)); }) .catch(error => { console.log(error); }); return ( <div className="App"> </div> ); } export default App;
如果一定要用require,需要调整为:
const axios = require('axios').default;
因为axios的CommonJS导出需要取.default才能拿到可调用的函数。
你的初始代码修正(结合代理方案)
如果使用Create React App的代理,调整后的代码如下:
import './App.css'; import axios from 'axios'; function App() { const target = { registrationNumber: 'AA19AAA' }; // Axios会自动处理JSON序列化,无需提前转换 const api_url = "/vehicle-enquiry/v1/vehicles"; function getData() { // axios.post的参数顺序:url、请求数据、配置项(headers等) axios.post(api_url, target, { headers: { 'x-api-key': 'API KEY HERE', 'Content-Type': 'application/json', } }) .then(res => { console.log(res.data); // DVLA返回的响应结构中没有content字段,直接打印res.data即可 }) .catch(err => { console.log(err); }) } return ( <div className="App"> <button onClick={getData}>Get Info</button> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Papgooner

