本篇要解決的問題
之前有寫過一篇〈用 Vue.js 製作圖片版 EDM 生成器〉,實際上也有給公司內的其他部門同事使用。不過有一個麻煩的點就是,生成器出來的會是一包壓縮檔,他們必須自己手動傳上 FTP 或是主機上,所以就會有一些像「怎麼使用 FTP 啊?」、「怎麼傳上去啊?」、「要傳到哪裡啊?」的問題。
這篇就是寫怎麼把在前端完成的檔案,POST 把檔案給後端後,後端把收到的檔案傳進 FTP 中的實作筆記。
本篇會有前端的 JavaScript,跟後端的 Node.js,Node.js 對 August 來說算是半熟,因此大部份都是安裝 npm Package 去完成一些需要的功能。
前端 JavaScript 傳送檔案
這邊的使用情境是使用者點擊 <input type="file">
去選擇要上傳什麼檔案。
前端抓取 file input 的部份可以看以前 August 寫過的這篇:
〈File API 客製上傳檔案按鈕 / input file〉
因為製作電子報時不會只有一張圖檔,還會有一個 HTML 的檔案,因此下面的程式碼是要抓取多個 file input 的。
先寫一個簡單的 HTML,就放 3 個 file input 跟一個送出的按鈕:
<input type="file" /> <input type="file" /> <input type="file" /> <button id="upload">送出</button>
JS 的部份就是點擊 #upload
的按鈕時會抓 3 個 input 裡的檔案,POST 到後端:
import 'idempotent-babel-polyfill';
這段是讓 JS 可以支援 Async、Await 的。
fileUploadHandler
用了 Promise,因為我們上傳的檔案是多個,就要讓這些檔案是一個一個輪流處理,同時一起出去的話實測過會掉檔案。
關於 Promise、Async、Await 可以看這篇,本篇就不多寫:
uploadUri
是我們把 Node.js 檔佈署上主機後會有的網址,後面一段的 Node.js 檔案上我們會寫 uploadFileToFTP
來監聽傳圖片來的 POST。
我們在這邊把檔案轉成 Form Data,名稱取叫「clientFile」,後面 Node.js 抓檔案時就要用這個檔案名稱來抓。
後端 Node.js 傳檔案到 FTP
我們要先安裝幾個 Package:
- Express
- cors:處理前端 Request 時會遇到的跨網域問題
- express-fileupload:處理接收到的檔案
- jsftp:把檔案傳送到 FTP
程式碼如下:
const Ftp …
這邊就是設定要傳到哪個 FTP 的資訊。
app.post('/uploadFileToFTP'…
這邊寫的就是當我們前們 POST 到 https://…/uploadFileToFTP
時要做些什麼事。
我們 console.log(req.files)
的話,會看到以下:
可以看到,因為我們在前端 POST 資料時,是把檔案 append 到 clieneFile
,因此我們在 Node.js 上取得的檔案是在 req.files.clientFile
裡。
參考 jsftp 的說明文件,新增檔案的程式碼如下:
Ftp.put(source, remotePath, callback); // 範例 ftp.put(buffer, "path/to/remote/file.txt", err => { if (!err) { console.log("File transferred successfully!"); } });
source
就是 req.files.clientFile.data
。
remotePath
就是我們想傳到 FTP 的哪個路徑上,最後面要加上檔案名稱才傳得上去。
callback
就是執行完 function 後要做什麼事情,範例上的是如果成功上傳就要印一句傳輸成功。