作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, 有興趣也能夠看看~