ทำระบบอัพโหลดไฟล์ด้วย Node.js

Published on
NodeJS
2015/03/upload-file-using-node-js
Discord

บทความนี้จะพูดถึงตัวอย่างการทำไฟล์อัพโหลดด้วยการใช้ Node.js + Express.js ร่วมกับ Middleware ของ Express.js ด้วย Multer สำหรับบทความนี้จะมีเทคโนโลยีที่เกี่ยวข้องดังนี้

Step 1 : Create Project

เริ่มต้นทำการสร้างโฟลเดอร์ขึ้นมาใหม่ จากนั้นสร้างไฟล์ package.json ขึ้นมา (หรือจะใช้คำสั่ง npm init ก็ได้)

mkdir file-upload
cd file-upload
touch package.json

ที่ไฟล์ package.json ตั้งชื่อโปรเจ็คและกำหนดเวอร์ชัน ผมกำหนดไว้แบบนี้

{
  "name": "file-upload",
  "version": "0.0.1"
}

ต่อมาติดตั้ง dependencies ที่จะใช้ คือ express และ multer

npm install express multer --save-dev

ไฟล์ package.json หลังจากที่ติดตั้ง dependencies เรียบร้อยแล้วจะได้ดังนี้

{
  "name": "file-upload",
  "version": "0.0.1",
  "devDependencies": {
    "express": "^4.12.3",
    "multer": "^0.1.8"
  }
}

Step 2 : index.html

ต่อมาทำการสร้างไฟล์ index.html ขึ้นมา ในส่วนนี้จะไม่ใช้ Template Engine เช่น Jade นะครับ เพราะว่าเป็นแค่ไฟล์อัพโหลดธรรมดา หน้าตา index.html ก็มีแค่นี้เอง

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Sample File Upload</title>
  </head>
  <body>
    <form action="/upload" method="post" enctype="multipart/form-data">
      <input type="file" name="file" />
      <input type="submit" value="Upload" />
    </form>
  </body>
</html>

กำหนด form ไปที่ /upload แบบ POST และกำหนดเป็น enctype="multipart/form-data" โดยในส่วนไฟล์อัพโหลด เราจะใช้ input เป็นแบบ file

Step 3 : server.js

ต่อมาในส่วน server.js ทำการเขียนโค๊ดเพื่อกำหนด route และรับ request & response ด้วย express.js แบบนี้

var express = require('express')
var app = express()

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

app.post('/upload', function (req, res) {
  res.send(req.files)
})

app.listen(5555, function () {
  console.log('App running on port 5555')
})

ทดสอบรันเซิฟเวอร์ดู

node server.js

จากนั้นเข้าเว็บ http://localhost:5555 และทำการอัพโหลดไฟล์หรือรูปภาพดู สังเกตผลลัพธ์

จะเห็นว่า ยังไม่มี result อะไรออกมา เนื่องจากตัว Express.js โดย default แล้ว มัน handle เฉพาะ urlencoded และ JSON ไม่รวม multipart ฉะนั้นต้องใช้ middleware อย่าง multer มาช่วย

Step 4 : Use multer

ที่ไฟล์ server.js ทำการ require multer เข้ามา จากนั้นเพิ่มโค๊ด

app.use(multer());

server.js จะได้เป็นแบบนี้

var express = require('express')
var multer = require('multer')

var app = express()
app.use(multer())

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

app.post('/upload', function (req, res) {
  res.send(req.files)
})

app.listen(5555, function () {
  console.log('App running on port 5555')
})

จากนั้นทำการ restart server อีกครั้ง ทดสอบอัพโหลดไฟล์ กด Upload ก็จะเห็นผลลัพธ์แสดงเป็นไฟล์ JSON แบบนี้

{
  "file": {
    "fieldname": "file",
    "originalname": "sample.png",
    "name": "02d6a43b22b6cd220336bc35d4e93c6b.png",
    "encoding": "7bit",
    "mimetype": "image/png",
    "path": "/tmp/02d6a43b22b6cd220336bc35d4e93c6b.png",
    "extension": "png",
    "size": 3947,
    "truncated": false,
    "buffer": null
  }
}

จะเห็นได้ว่า ไฟล์ที่เราอัพโหลด เราสามารถรู้ค่า properties ได้ อย่างเช่น

  • originalname : ชื่อไฟล์ที่เราอัพโหลด
  • name : ชื่อไฟล์หลังจากที่อัพโหลด
  • mimetype : ชนิดของไฟล์
  • path : location ที่เก็บไฟล์หลักจากถูกอัพโหลด (default น่าจะถูกเก็บไว้ที่ temp)
  • extension : นามสกุลไฟล์

ที่นี้เราจะทำอะไรกับไฟล์ที่อัพโหลดก็สามารถทำได้

ถ้าเป็นระบบจริงๆ เมื่อทำการอัพโหลดไฟล์ควรจะกำหนดสิทธิ์ หรือลบออกจาก file system ไม่เช่นนั้น server คุณอาจจะถูก bomb จากการอัพโหลดไฟล์เข้ามาจนเซิฟเวอร์ล่มได้ :)

Step 5 : Multer Configuration

สุดท้าย เราสามารถที่จะกำหนดค่า multer ต่างๆได้ เช่น

  • เปลี่ยนชื่อไฟล์ที่อัพโหลด โดย generate ตาม timestamp
  • กำหนด path ที่เก็บไฟล์ เช่น ไว้ที่โฟลเดอร์ /uploads
  • จำกัดขนาดไฟล์ให้ไม่เกิน 1 MB

ที่ไฟล์ server.js ตรงส่วน app.use(multer()); เราสามารถส่ง object ที่ใช้กำหนดค่าได้แบบนี้

var fs = require('fs')

app.use(
  multer({
    dest: __dirname + '/uploads/',
    rename: function (fieldname, filename) {
      return Date.now()
    },
    limits: {
      fileSize: 100000
    },
    onFileSizeLimit: function (file) {
      console.log('Failed: ' + file.originalname + ' is limited')
      fs.unlink(file.path)
    }
  })
)
  • dest : ไว้กำหนด location ที่เก็บไฟล์
  • rename : เปลี่ยนชื่อไฟล์ที่อัพโหลด
  • limits : ไว้กำหนด limit ต่างๆ เช่น ขนาดไฟล์ ความยาวชื่อไฟล์ เป็นต้น
  • onFileSizeLimit : ฟังค์ชันที่ทำงานเมื่อไฟล์เกินลิมิตที่กำหนด

ทีนี้เวลาอัพโหลดไฟล์ลงไปใหม่ path ที่เก็บไฟล์ ชื่อไฟล์ ก็จะถูกเปลี่ยนตามที่เรากำหนด options ไว้ครับ

สุดท้าย ไฟล์ server.js เป็นแบบนี้ครับ

var express = require('express')
var multer = require('multer')
var fs = require('fs')

var app = express()

app.use(
  multer({
    dest: __dirname + '/uploads/',
    rename: function (fieldname, filename) {
      return Date.now()
    },
    limits: {
      fileSize: 100000
    },
    onFileSizeLimit: function (file) {
      console.log('Failed: ' + file.originalname + ' is limited')
      fs.unlink(file.path)
    }
  })
)

app.get('/', function (req, res) {
  res.sendFile(__dirname + '/index.html')
})

app.post('/upload', function (req, res) {
  res.send(req.files)
})

app.listen(5555, function () {
  console.log('App running on port 5555')
})

สรุป

ตัวอย่างนี้ก็เป็นการทำไฟล์อัพโหลดแบบง่ายๆ ด้วยวิธีของผมเองนะครับ ไม่ชัวร์ว่าจะเป็น Best Practice หรือเปล่า ด้วย Node.js + Express.js + Multer เท่านั้นครับ หากมีตรงไหนผิดพลาด แนะนำเพิ่มเติมได้ครับ หรือหากต้องการรายละเอียดเพิ่มเติม ก็สามารถอ่านได้ที่ references

References

Buy Me A Coffee
Authors
Discord