山地人

第005期.axios在Vue项目里如何正确使用?

山地人
山地人
2021-05-13

第005期.axios在Vue项目里如何正确使用?

作者:山地人

现在很多用Vue搭建的新项目,很多小伙伴使用axios来作为前后端的Http通讯库。但是刚接触这块的小伙伴可能会立即碰上两个问题。

1.跨域问题:Vue的前端项目和后台API不在同一个域名端口下,用axios发送请求遇到跨域报错

img

2.用axios发送post请求后台报400错误,一头无数有木有?

2711555125921_.pic_hd

如果你被这两个问题困扰到了,那么很幸运这篇文章应该是你的菜。

为何会遇上跨域问题?

在前后端不分离的时代,前端的页面都是作为后台的页面部分由后台程序直接输出到浏览器中。所以浏览器中的页面和后台API都是在相同的域名和相同的端口下。这种时候就没有跨域问题,服务器启动一个8080端口,页面里的API请求 /login 都是指向自己的8080端口,一切都是那么平和。

自从进入前后端分离时代,后台工程师已经不管页面浏览器的事,专注于写API接口。而所有和用户能够直接接触到的内容都交给了我们的前端工程师来处理。这个时候前端开发人员再开发项目时就变成了自己开启一个独立的服务(比如:Vue CLI 中我们用 npm run serve 或者你也可以用 http-server . 等启动一个静态页面服务器)。你的页面可能启动在 http://localhost:8080/, 后台开发给你的API网址是 http://api.myproject.com:3000/。这是在你本地的http://localhost:8080/站点页面下访问http://api.myproject.com:3000/站点下的API时就会遇到跨域问题。原因是**正常情况下**浏览器为了安全考虑,**A域名:A端口**下的网页去调用 B域名或者A域名:B端口的内容。你想如果你站点的后台API可以被其他网站的页面随意调用那是不是非常不安全。

但是这个限制是发生在浏览器端访问后台API上,对于后台服务器来说。服务器之间的相互通讯就是非常正常的需求。你想,稍微有些规模的公司都不可能只有一个后台服务,不同的服务之前相互访问是非常正常的事情。所以在后台API之间就不存在跨域的问题。因此我们解决跨域问题的原理就是让浏览器页面还是调用自己本端口的服务,再由自己的后台服务去和API服务器做通讯。此时我们的后台服务也就起到了代理的作用,这也就是但是了我们的代理proxy的概念。

问题1.前后端分离的项目,在Vue中如何解决请求跨域问题?

好的,我们在了解了用proxy代理来解决跨域问题后。接下来我们要解决的问题就是操作层面的问题了。如何在Vue项目中配置proxy代理。这个其实也非常容易。

  1. 首先我们在Vue CLI的官网中找到配置proxy的相关说明 参考此处
  2. 在我们的项目根目录下创建vue.config.js文件,做如下配置:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000/',
},
}
}
}

这里简单说明一下上面的配置的含义,首先vue.config.js配置文件是用来定制我们vue cli脚手架的配置文件。

  • devServer:这里的devServer是配置我们每次用 npm run serve启动的后台服务。
  • proxy:就是配置代理的字段。
  • ‘/api’:这里面的’/api’是告诉我们启动的这个后台服务要代理的URL类型,比如这里我们要代理的是 /api开头的这些url。
  • target:是要代理到的目标服务器的网址(注意这里不用添加/api,因为比如你在页面发送的 axios.get(‘/api/login’) 的请求/api/login会在这个服务器内部自动进行组合,最后会生成 http://localhost:3000/api/login)

配置好上面的proxy代理后,你就可以像在你本站访问本站API一样去使用这些API了。

axios.get(`/api/userInfo`).then(resp=>{
console.log("获得的数据:",resp.data);
});

问题2.用axios发送POST请求怎么收到了400错误,明明参数都正确

这个可能是很多解决了第一个问题的小伙伴紧接着会遇到的第二个问题。问题的根源是什么?其实我们用axios发送的post请求默认是配置的请求头为json格式的,也就是说我们发送给我们的服务器的数据是json格式的数据。但是我们的后端开发人员的接收的post请求类型却只支持x-www-form-urlencoded格式提交的数据。

那这是要解决这个问题,有两个途径:

  1. 找我们的后台大哥,帮我们支持下json格式的post请求。当然如果后台大哥心情比较好或者比较空闲顺手把这事做了,问题也就搞定了。但如果碰到后台大哥比较忙或者后台大哥比较low不知道如何支持json格式的post请求,那这条路也就失效了。
  2. 找大哥不行,是不是就搞不定这个问题了呢?当然不能,我们前端有我们自己的解决方法。你后台不是只支持x-www-form-urlencoded格式提交的数据么,好,我就依你的要求去提交这种格式的post请求不就行了吗。具体的写法看下文的代码。
import axios from 'axios';
import qs from 'qs';
const data = {
userName,
password,
};
axios.post(`/api/login`,qs.stringify(data),{
headers:{
'content-type': 'application/x-www-form-urlencoded'
}
}).then(resp=>{
console.log("成功获得后台大哥返回的数据:",resp.data);
});

用axios提交x-www-form-urlencoded格式的数据有两个注意事项:

  1. 要在axios的请求头重设定content-type类型为‘application/x-www-form-urlencoded’,这样后台收到你的请求后,就知道你提交的是传统的Form表单数据
  2. 另外要注意的地方是,你发送的数据要用 qs.stringify(data) 进行转码处理。

做好这两步后台API就能乖乖为你服务了。

这里附上我为你准备的完整的前端用Vue CLI+axios,后端用express做的Demo演示。你可以结合本文内容和演示Demo一起来看,理论加实践,让你彻底搞明白这两个问题。GitHub演示代码

上面是我们在进行前后端分类项目时,解决跨域问题和发送POST请求时经常会遇到的两个问题。不光使用与Vue+axios的项目。其实只要是单页面的SPA项目,前后台接口做了分离的都可以用本文的原理方法去解决应对。

希望山地人为你准备的这篇文章对你有所帮助。