博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用ElementUI和Axios以formData格式提交带有文件的表单的错误示范及分析解决
阅读量:7155 次
发布时间:2019-06-29

本文共 4311 字,大约阅读时间需要 14 分钟。

做Vue项目的时候, 提交数据基本上都是用Axios, 之前做过的表单方面的提交, 并没有过多关注客户端和服务器之间的通信过程. 所以一直对HTTP的head请求头, body内容之类的不明不白, 为了短期(是的估计过半年又忘了?)解决这个疑惑, 再次复习了一遍. 顺便总结了
Vue中使用Axios处理包含上传文件的表单提交

场景说明

项目使用的Vue(Nuxt)框架, 数据请求用的插件, 表单包含了一些基本的用户信息填写, 同时还有身份证上传, 和后端沟通过, 提交数据的时候, 接口全部使用请求, 那么有文件上传的一般来说只能用formData格式.

实践及代码示例

我项目中使用的是ElementUI, 对于不熟悉的朋友, 需要注意几个事情:

  • action是必填, 那么留空也许是个不错的做法.
  • 获取到上传的文件的办法很多. 官方提供了几种事件来获取, 例如: on-success, on-change(首次上传会触发两次), 我这里使用了on-success
  • 那么拿到上传的回调, 这里特别需要注意的, 我以on-success三个参数来看

    • response是服务器返回的响应
    • file一个文件
    • fileList存放多个文件的数组
可能看到有
file或者
fileList会直接将它的数据提交给后台, 一开始我也是没注意到这点, 始终无法正确提交数据. 那么经过一番研究和排查, 得知:
真正的File对象是fileList数组中某个元素的raw属性!, 那么下面先看一段错误的示范:

页面部分结构代码如下:

点击上传
只能上传jpg/png文件,且不超过500kb
提交
取消

这里我将上传文件数量限制为1个, 接下来是JavaScript部分:

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对象是什么鬼, 没有这方面经验的人肯定就搞不清怎么回事了. 所以一般对这块不熟悉的人容易犯以下的几个错误:

  • 不了解上传文件应该以什么方式提交, 比如后台是multipart/form-data, 而习惯性以json对象发送数据(因为大量插件对数据对象也封装了方法, 所以容易忽略)
  • 不知道上传文件提交的格式, 以为将this.fileList改成this.fileList[0]就万事大吉
  • 当多种疑惑无法解决的时候, 可能会尝试很多次都不行, 陷入误区而久久无法解决困难. 开始怀疑是否是Axios插件不支持文件上传.
  • 其他各种别的问题...

问题解决

其实, 熟悉的话, 解决这个问题很简单. 前面也说过, elementUI将返回的file对象封装了一下, 首先我们要拿到真正的文件对象, 实际上就是file.raw或者fileList[0].raw!

不要以为这样就可以提交数据了. 我们还要使用form-data特有的提交方式来提交带有文件内容的表单. 废话不多说上一段, 修正后的部分代码:

点击上传
只能上传jpg/png文件,且不超过500kb
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)    })}

简单说明下

  • 其实elementUI中提供了一个http-request事件来覆盖默认的action, 这样很好的避免了一些异常(比如我在测试环境的时候, 用了不太好的的on-success通过了验证, 但是在生产环境中由于action地址空所以默认请求当前地址, 出现了404).
  • formData似乎只能一个个对应的append进去, console出来也看不到, 具体用法可以参考文章末尾的MDN~
  • axios是可以很好地完成formData表单数据提交的, 这里虽然也是一个对象, 但是不是普通的json对象, 他对这个数据处理很正常, 所以放心使用.

额外补充: axios配置

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后再发送请求给服务器的.

总结

好了说了一大堆, 其实最重要的事情是, 理解以下几点

  • 和后端沟通好, 请求格式
  • 了解上传文件需要的表单数据格式
  • 尽量多的去熟悉第三方UI插件, 尤其像elementUI这样相对完善的组件, 应该是有较好的处理方法的
  • 耐心的一步步查找错误

最后献上一些参考资料:

文中难免也有一些描述不准确的地方, 希望大佬们多多指点~ 本文提到的代码的存放在GitHub上面nuxt-spa-demo项目的分支, 有兴趣也可以看看~

转载地址:http://cgegl.baihongyu.com/

你可能感兴趣的文章
IOS开发:xcode5版本引发的问题
查看>>
asp.net 负载均衡下session存储的解决方法
查看>>
构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(17)-LinQ动态排序
查看>>
领域驱动开发推荐代码示例 — Microsoft NLayerApp
查看>>
Linux 安装Rsync和配置
查看>>
hadoop fs -mkdir testdata错误 提示No such file or directory
查看>>
zebra路由软件使用大全
查看>>
PostgreSQL security - don't use password method in pg_hba.conf
查看>>
RDS MySql支持online ddl
查看>>
在Hudson中,使用ant自动对安卓项目编译打包apk
查看>>
【JSP开发】利用request获取各种值
查看>>
Vue全家桶web端社区项目
查看>>
多次Push Pop导致的`Can't add self as subview`问题
查看>>
从萌新的角度理解JVM内存管理
查看>>
d3.js 关于力引导图的简单解析
查看>>
pm2实践指南
查看>>
preload和prefetch
查看>>
rhel6 nfs共享
查看>>
LINUX下调节屏幕亮度(Intel核显)-续
查看>>
webstorm/phpstorm的Tab换4个空格
查看>>