如何在Node.js的Express中使用相对URL调用REST API?
问题:Express中使用Axios调用同应用API时的URL错误问题
我在Express控制器中有如下代码:
const http = require('axios'); module.exports = { login: (req, res) => { res.render("admin/login.ejs", { errorMessage: req.flash('message')[0] }); }, processLogin: (req, res) => { axios.post(`/api/login`, { "email": req.body.email, "password": req.body.password }) .then(function(response) { console.log(response); }) .catch(function(error) { console.error(error); }); } }
其中路径"/api/login"是同一应用中Express路由定义的API,但出现如下错误:
TypeError [ERR_INVALID_URL]: Invalid URL at new NodeError (node:internal/errors:372:5) at URL.onParseError (node:internal/url:553:9) at new URL (node:internal/url:629:5) at dispatchHttpRequest (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:2394:20) at new Promise (<anonymous>) at http (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:2330:10) at Axios.dispatchRequest (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:3260:10) at Axios.request (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:3610:33) at Axios.httpMethod [as post] (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:3649:19) at Function.wrap [as post] (D:\projects\calvarycomz.com\node_modules\axios\dist\node\axios.cjs:27:15) { input: '/api/login', code: 'ERR_INVALID_URL' }
我知道错误源于Axios请求地址缺少主机前缀(如http://localhost:30000),请问如何仅用URL路径通过Axios发起HTTP请求?
解决方案
方法1:直接调用路由处理函数(推荐)
同应用内的API没必要走HTTP请求,直接导入对应的路由处理函数调用更高效,也能彻底避免URL问题。
假设/api/login的处理函数定义在routes/api.js中:
// 控制器中先导入路由处理函数 const { loginHandler } = require('../routes/api'); module.exports = { login: (req, res) => { res.render("admin/login.ejs", { errorMessage: req.flash('message')[0] }); }, processLogin: (req, res) => { // 直接调用路由处理函数 loginHandler(req, res) .then(() => { // 处理成功逻辑 }) .catch(error => { console.error(error); // 处理错误逻辑 }); } }
方法2:配置Axios的baseURL
如果必须用Axios发起请求,可通过配置baseURL让后续请求只需写路径。
全局配置Axios
在项目入口文件(如app.js)中全局配置:
const axios = require('axios'); // 用环境变量或固定端口设置baseURL axios.defaults.baseURL = `http://localhost:${process.env.PORT || 3000}`;
之后控制器中就能直接用路径发起请求:
axios.post('/api/login', { email: req.body.email, password: req.body.password }) .then(response => console.log(response)) .catch(error => console.error(error));
动态生成baseURL
从当前请求对象req中获取主机信息,动态拼接baseURL,适配不同运行环境:
processLogin: (req, res) => { const baseURL = `${req.protocol}://${req.get('host')}`; axios.post(`${baseURL}/api/login`, { email: req.body.email, password: req.body.password }) .then(response => console.log(response)) .catch(error => console.error(error)); }
方法3:创建专用Axios实例
如果不想污染全局配置,可以创建一个专门用于内部请求的Axios实例:
const axios = require('axios'); // 创建实例并设置baseURL const internalAxios = axios.create({ baseURL: `http://localhost:${process.env.PORT || 3000}` }); module.exports = { login: (req, res) => { res.render("admin/login.ejs", { errorMessage: req.flash('message')[0] }); }, processLogin: (req, res) => { // 使用专用实例发起请求 internalAxios.post('/api/login', { email: req.body.email, password: req.body.password }) .then(response => console.log(response)) .catch(error => console.error(error)); } }
内容的提问来源于stack exchange,提问作者Jordy
相关产品推荐
相关产品推荐

