一般情況下,前端的檔案上傳一般都是通過form表單的(<input type=”file” />)來完成檔案的上傳,如果使用node中間層完成跨域,檔案的上傳就需要在node中間層處理成可讀流,轉成formData完成轉發。
一、form表單檔案上傳
這是最常見的檔案上傳方式,通過form表單實現,簡單實用,設定一下method、enctype、action屬性就可以了,多檔案上傳需要設定multiple屬性(部分瀏覽器支援還是有些問題的)。
1 <form method="post" enctype="multipart/form-data" action="/api/upload"> 2 <input type="text" name="username"> 3 <input type="password" name="password"> 4 <input type="file" name="file"> 5 <input type="submit"> 6 </form>
二、FormData實現檔案上傳
FormData物件用以將資料編譯成鍵值對,以便向後臺傳送資料。其主要用於傳送表單資料,但亦可用於傳送帶鍵資料(keyed data),而獨立於表單使用。對部分瀏覽器對multiple屬性不支援的情況,可以使用formData的提交方式完成。
1 <!-- 獲取上傳檔案轉成formData型別的檔案 --> 2 <input multiple id="file" name="file" type="file" /> 3 <button id="btn">提交</button>
1 const oFile = document.getElementById(`file`) 2 const oBtn = document.getElementById(`btn`) 3 4 oBtn.addEventListener(`click`, () => { 5 files = oFile.files 6 const formData = new FormData() 7 formData.append(`file`, files[0]) 8 formData.append(`file1`, files[1]) 9 10 fetch(`/api/upload`, { 11 method: "POST", 12 body: formData 13 }) 14 })
- 使用fetch請求不要設定Content-Type,否則無法請求
- fetch請求預設是不帶cookie
三、node中間層完成檔案上傳跨域
跨域是因為瀏覽器的同源策略造成,跨域的方法有很多中,這裡使用的是node中間層代理完成(服務端之間的請求是不存在跨域問題)。
node無法直接解析上傳的檔案,需要引入擴充包connect-multiparty完成,這樣就可以拿到檔案資料。
拿到上傳檔案,需要在node中轉發請求後臺server,這裡的檔案不能直接發給後臺,需要將上傳的檔案使用fs.createReadStream轉成可讀流,同時引入 form-data 包(node環境是沒有formData物件的),這樣就可以實現node中間層轉發檔案型別
node部分程式碼:
1 const fs = require(`fs`) 2 const path = require(`path`) 3 const FormData = require(`form-data`) 4 const express = require(`express`) 5 const fetch = require(`node-fetch`) 6 const router = express.Router() 7 const multipart = require(`connect-multiparty`); 8 var multipartMiddleware = multipart() 9 10 router.post(`/upload`, multipartMiddleware, function (req, res) { 11 // console.log(req.body, req.files); 12 13 const { path: filePath, originalFilename } = req.files.file 14 const newPath = path.join(path.dirname(filePath), originalFilename) 15 16 fs.rename(filePath, newPath, function (err) { 17 if (err) { 18 return; 19 } 20 else { 21 const file = fs.createReadStream(newPath) 22 const form = new FormData() 23 form.append(`file`, file) 24 25 fetch(`http://localhost:8080/upload`, { 26 method: "POST", 27 body: form 28 }) 29 } 30 }) 31 res.json({}) 32 }); 33 34 module.exports = router;
注意:
- node無法直接解析上傳檔案,需要引入npm包connect-multiparty中介軟體,或者引入npm包multiparty
- node拿到檔案,需要使用fs.createReadStream轉成可讀流
- node環境沒有formData物件,需要引入npm包form-data
- fetch請求提交formData資料,不能設定Comtemt-Type
完整的程式碼請參考 node中間層實現檔案上傳