作Vue项目的时候, 提交数据基本上都是用Axios, 以前作过的表单方面的提交, 并无过多关注客户端和服务器之间的通讯过程. 因此一直对HTTP的head请求头, body内容之类的不明不白, 为了短时间(是的估计过半年又忘了😂)解决这个疑惑, 再次复习了一遍. 顺便总结了 Vue中使用Axios处理包含上传文件的表单提交
项目使用的Vue(Nuxt)框架, 数据请求用的Axios插件, 表单包含了一些基本的用户信息填写, 同时还有身份证上传, 和后端沟经过, 提交数据的时候, 接口所有使用POST请求, 那么有文件上传的通常来讲只能用formData格式.javascript
我项目中使用的是ElementUI, 对于上传组件不熟悉的朋友, 须要注意几个事情:html
on-success
, on-change
(首次上传会触发两次), 我这里使用了on-success
那么拿到上传的回调, 这里特别须要注意的, 我以on-success
三个参数来看vue
response
是服务器返回的响应file
一个文件fileList
存放多个文件的数组可能看到有file
或者fileList
会直接将它的数据提交给后台, 一开始我也是没注意到这点, 始终没法正确提交数据. 那么通过一番研究和排查, 得知: 真正的File对象是fileList
数组中某个元素的raw
属性!, 那么下面先看一段错误的示范:
页面部分结构代码以下:java
<el-form ref="form" :model="form" label-width="120px"> <el-form-item label="活动名称"> <el-input v-model="form.name"></el-input> </el-form-item> <el-form-item label="活动区域"> <el-select v-model="form.region" placeholder="请选择活动区域"> <el-option label="区域一" value="shanghai"></el-option> <el-option label="区域二" value="beijing"></el-option> </el-select> </el-form-item> <el-form-item label="身份证正面"> <el-upload action="" :on-success ="handleSuccess" :multiple="false" :limit="1" :on-exceed="handleExceed" :file-list="fileList"> <el-button size="small" type="primary">点击上传</el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload> </el-form-item> <el-form-item> <el-button type="primary" @click="onSubmit">提交</el-button> <el-button>取消</el-button> </el-form-item> </el-form>
这里我将上传文件数量限制为1
个, 接下来是JavaScript部分:ios
import AppLogo from '~/components/AppLogo.vue' export default { components: { AppLogo }, data() { return { form: { name: '', region: '' }, fileList: [] } }, methods: { handleSuccess(response, file, fileList) { this.fileList = fileList }, handleExceed(files, fileList) { this.$message.warning(`最多上传 ${files.length} 个文件`) }, onSubmit() { this.$axios .$post('/api/active', { name: this.form.name, region: this.form.region, file: this.fileList }) .then(response => { if (response.code === 200) { // 提交成功将要执行的代码 } }) .catch(function(error) { // console.log(error) }) } } }
上面的这段
onSubmit
能提交成功就是真的见了鬼呢
问题在哪呢, 前面提到, 后台接受数据的格式是multipart/form-data
, 你发个json对象是什么鬼, 没有这方面经验的人确定就搞不清怎么回事了. 因此通常对这块不熟悉的人容易犯如下的几个错误:git
multipart/form-data
, 而习惯性以json对象发送数据(由于大量插件对数据对象也封装了方法, 因此容易忽略)this.fileList
改为this.fileList[0]
就万事大吉其实, 熟悉的话, 解决这个问题很简单. 前面也说过, elementUI将返回的file
对象封装了一下, 首先咱们要拿到真正的文件对象, 实际上就是file.raw
或者fileList[0].raw
!github
不要觉得这样就能够提交数据了. 咱们还要使用form-data
特有的提交方式来提交带有文件内容的表单. 废话很少说上一段, 修正后的部分代码:element-ui
<el-upload action="" :http-request="handleFile" :multiple="false" :limit="1" :on-exceed="handleExceed" :file-list="fileList"> <el-button size="small" type="primary">点击上传</el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload>
onSubmit() { let form = this.$refs['form'].$el let formData = new FormData(form) formData.append('name', this.form.name) formData.append('region', this.form.region) formData.append('file', this.fileList[0]) this.$axios .$post('/api/active', formData) .then(response => { if (response.code === 200) { // 提交成功将要执行的代码 } }) .catch(function(error) { // console.log(error) }) }
简单说明下json
http-request
事件来覆盖默认的action, 这样很好的避免了一些异常(好比我在测试环境的时候, 用了不太好的的on-success
经过了验证, 可是在生产环境中因为action地址空因此默认请求当前地址, 出现了404).Axios能够说在Vue中至关重要, 常常咱们对简单的从新封装或者配置, 就这个插件来讲彻底能够写一篇新文章了, 这里他不是重点我就简单介绍下我用它作的配置
import qs from 'qs' import { Message } from 'element-ui' export default function({ $axios, redirect }) { let apiUrl = process.env.apiUrl $axios.defaults.baseURL = apiUrl $axios.defaults.timeout = 15000 $axios.defaults.headers.post['Content-Type'] = 'multipart/form-data' $axios.onRequest(config => { // 与后台配合post请求字符串传参 let reqParams = qs.stringify(config.data) let url = config.url + (reqParams ? '?' : '') + reqParams config.url = url }) $axios.onResponse(res => { if (res.data.code !== 200) { // 后台返回session过时或异常的状况 if (res.data.code === 401 || res.config.url === apiUrl + '/logout') { window.sessionStorage.clear() redirect('/platform/login') } else { // 返回到一个错误页面或者提示错误 Message.error(res.data.message) // redirect('/') } } }) $axios.onError(error => { Message.error('服务器异常,请稍后再试') }) }
上面对发送数据请求的相关参数配置了, 也作了拦截器. qs
插件是个亮点, 我为了vue代码书写更清晰, 将json
对象传过来处理为name=whidy&age=30
相似这样的拼接到url后再发送请求给服务器的.axios
好了说了一大堆, 其实最重要的事情是, 理解如下几点
最后献上一些参考资料:
文中不免也有一些描述不许确的地方, 但愿大佬们多多指点~ 本文提到的代码的存放在GitHub上面nuxt-spa-demo项目的分支nuxt-axios-formdata, 有兴趣也能够看看~