Vue.js布局组件调用API路径异常问题求助
问题背景
我在Vue.js项目里采用topbar、sidebar、bottombar作为全局布局组件,所有视图渲染时都会加载这些组件。在topbar组件的beforeMount钩子中调用后端API获取数据,但遇到了一个头疼的问题:请求URL会随着当前视图的路径变化——本该固定调用https://localhost:44380/api/Timesheets/LoadLoggedUserDeputies,实际却变成了https://localhost:44380/Activities/api/Timesheets/LoadLoggedUserDeputies或https://localhost:44380/Reports/api/Timesheets/LoadLoggedUserDeputies,哪怕调用方是同一个布局组件也会出现这种情况。
现有代码
Vue组件中的请求代码:
beforeMount() { this.loggedUserDeputies.userDeputies = []; console.log("calling LoadLoggedUserDeputies"); $.get('api/Timesheets/LoadLoggedUserDeputies') .then(response => response as Promise<LoggedUserDeputies>) .then(data => { this.loggedUserDeputies = data; }); }
后端API控制器方法:
[Route("api/[controller]/[action]")] public object LoadLoggedUserDeputies() { if (ActualUserContract.LoggedUserDeputies == null) { return null; } var result = ActualUserContract.LoggedUserDeputies .ToList() .Select(x => new { userContractId = x.UserContract.Id, userContractFullName = x.UserFullName, userContractPersonalNumber = x.UserContract.PersonalNumber }); return new { userDeputies = result }; }
解决方案
下面提供几种实用的解决办法,你可以根据项目情况选择:
1. 使用带环境变量的绝对URL(最稳妥)
直接使用完整的绝对URL发起请求,但为了避免硬编码环境地址,建议把API基础地址配置到Vue的环境变量中:
首先在项目根目录的.env.development(开发环境)和.env.production(生产环境)文件中分别配置:
# .env.development VUE_APP_API_BASE_URL=https://localhost:44380 # .env.production VUE_APP_API_BASE_URL=https://your-production-domain.com
然后修改请求代码:
beforeMount() { this.loggedUserDeputies.userDeputies = []; console.log("calling LoadLoggedUserDeputies"); const apiUrl = `${process.env.VUE_APP_API_BASE_URL}/api/Timesheets/LoadLoggedUserDeputies`; $.get(apiUrl) .then(response => response as Promise<LoggedUserDeputies>) .then(data => { this.loggedUserDeputies = data; }); }
这种方式不管当前视图路径是什么,都会请求固定的完整URL,适配所有环境。
2. 全局配置jQuery Ajax的baseURL
如果你的项目大量使用jQuery发起请求,可以全局设置Ajax的基础地址,这样所有请求都会自动拼接这个前缀:
在Vue项目的入口文件(比如main.js)中添加以下配置:
// 可以结合环境变量使用,避免硬编码 $.ajaxSetup({ baseUrl: process.env.VUE_APP_API_BASE_URL + '/' });
之后你的请求代码就可以保持原来的相对路径写法,jQuery会自动拼接baseUrl:
$.get('api/Timesheets/LoadLoggedUserDeputies')
3. 开发环境使用Vue代理配置
如果是开发阶段,前后端跨域或者路径问题,可以在vue.config.js中配置代理,让前端请求转发到后端地址:
module.exports = { devServer: { proxy: { '/api': { target: 'https://localhost:44380', changeOrigin: true, // 如果后端路由没有/api前缀,可以加pathRewrite去掉 // pathRewrite: { '^/api': '' } } } } }
然后修改请求路径为根相对路径(开头加斜杠):
$.get('/api/Timesheets/LoadLoggedUserDeputies')
这样开发环境下请求会被代理到后端地址,生产环境如果前后端部署在同一域名下,也可以直接使用这个路径;如果生产环境是跨域名,还是建议用第一种方法。
问题原因分析
你当前使用的是相对路径(没有开头的斜杠),浏览器会以当前页面的URL作为基准来拼接请求地址。比如当前视图在/Activities路径下,相对路径api/Timesheets/...就会被拼接到/Activities/后面,形成/Activities/api/...的错误URL。如果路径开头加上斜杠(/api/Timesheets/...),会基于域名根目录拼接,但这只适用于前后端同域名的场景;跨域名的话,还是需要使用绝对URL或者代理方案。
内容的提问来源于stack exchange,提问作者phepa

