การใช้ use: คุณกำลังดูกระทู้
เนื้อหาต่อไปนี้ จะเป็นการทำความรู้จักกับ Routing ใน Express
รวมทั้งรูปแบบ และการใช้งานเบื้องต้น เพื่อเป็นแนวทางสำหรับ
เนื้อหาต่อๆ ไป เกี่ยวกับ Express
ต่อจากบทความ Express web framework เบื้องต้น http://niik.in/906
เรามาดูไฟล์ app.js ที่เราได้ทดสอบรันผ่าน บราวเซอร์มาแล้ว
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const port = 3000 // port // ส่งกลับข้อความ "hello world" เมื่อมี GET request มายังหน้า homepage app.get('/', function (req, res) { res.send('hello world ') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
Table of Contents
Routing คืออะไร
Routing คือการกำหนด URL หรือ Path ที่ใช้ในการเรียกข้อมูลผ่าน HTTP request เช่น
GET POST PUT หรือ DELETE แล้วให้ทำการ response หรือส่งกลับข้อมูลหรือการทำงานใดๆ
ให้สอดคล้องกับ URL ใดๆ ที่ระบุเข้ามา
การ response หรือส่งกลับข้อมูลด้วยการทำคำสั่งใดๆ นั้น เราสามารถกำหนดได้ว่า จะให้ทำคำสั่ง
เดียวหรือหลายคำสั่ง เมื่อผู้ใช้ request เข้ามายัง path และเข้าเงื่อนไขการทำงาน ยกตัวอย่าง
จากโค้ดด้านบน
app.get('/',function(){});
รูปแบบการกำหนด Route
app.METHOD(PATH, HANDLER)
โดย
app คือ instance ของ express (เข้าใจง่ายๆ “ฉัน (app)” คือตัวแทนของ express )
METHOD คือ HTTP request method ใช้เป็นตัวเล็ก หมายถึง ทำการเรียกข้อมูลผ่าน HTTP ด้วยวิธี
* get | post | put | delete
PATH คือ URL หรือ ส่วนของโดนเมนนับตั้งแต่ “/” ตัวที่ 3 เป็นต้นไป เช่น
*http://niik.in/forum จะได้ PATH คือ “/fourn” ถ้าเป็น Root PATH ก็คือ “/”
HANDLER คือฟังก์ชั่นที่กำหนดให้ทำงาน เมื่อ PATH ตรงกับค่าที่กำหนด
โค้ดด้านล่าง แสดงถึงการกำหนด Route อย่างง่าย โดย response หรือส่งกลับคำว่า “hello world”
ไปแสดงที่หน้าแรก หรือ homepage
// ส่งกลับข้อความ "hello world" เมื่อมี GET request มายังหน้า homepage app.get('/', function (req, res) { res.send('hello world ') })
Express ไม่เพียงแค่รองรับ GET POST PUT หรือ DELETE method แต่ยังสามารถรองรับ method ต่างๆ
ตามลิสรายการด้านล่าง โดยวิธีการทำงาน ก็จะสัมพันธ์กับชื่อที่ใช้เรียก Method นั้นๆ แต่อย่างไรก็ตาม
การใช้งานส่วนใหญ่เกือบทั้งหมด ก็จะเป็นการใช้งานใน 4 method ข้างต้น
Route methods
Route method นั้นถูกแปลงมาจาก HTTP method แล้วนำมาผูกเข้ากับ instance ของ express class
ตัวอย่างด้านล่าง คือโค้ดบางส่วนของการกำหนด route แบบ GET และ POST method ให้กับ Root ของ app
// GET method route app.get('/', function (req, res) { res.send('GET request to the homepage') }) // POST method route app.post('/', function (req, res) { res.send('POST request to the homepage') })
โดยเมื่อมี HTTP request ขึ้น ก็จะทำให้เกิด request object และ response object โดย object ทั้งสอง
เราสามารถนำเข้าไปใช้งานในฟังก์ชั่น เพื่อกำหนด หรือทำงานต่างๆ ต่อไปได้ ในโค้ดตัวอย่างใช้ตัวแปรอักษร
3 ตัวแบบย่อคือ req = request และ res = response
ตัวอย่าง ค่า req บางค่าก็เช่น req.url หรือ req.method เป็นต้น
ตัวอย่าง ค่า res บางค่าก็เช่น res.rawHeaders หรือ res.statusCode เป็นต้น
นอกจาก Method ต่างๆ ข้างต้นแล้ว ยังมี method พิเศษ ในการกำหนด Routing คือ app.all() ซึ่งใช้สำหรับ
กำหนดให้ทำงานใน middleware ฟังก์ชั่น หรือ ฟังก์ชั่นที่ใช้สำหรับจัดการกับ HTTP request ทุก method
ใดๆ ก็ตามที่เกิดขึ้น เข้าใจอย่างง่ายก็คือ สมมติเกิด GET request มาที่ “/” เราสามารถใช้ฟังก์ชั่น middleware
มาดักจับตัว request แล้วปรับปรุงเปลี่ยนแปลงค่าต่างๆ ก่อนที่ค่านั้น จะผ่านเข้ามาในฟังก์ชั่น HANDLER ของ
method นั้น ยกตัวอย่าง เราเพิ่มโค้ด การใช้งาน app.all() เข้าไปก่อนการ เรียกใช้ GET method ดังนี้
// ดักจับทุกๆ method app.all('/', function (req, res, next) { console.log('Accessing the secret section ...') res.myobj = 1; // สมมติเราเพิ่ม req property ที่ชื่อ myobj เท่ากับ 1 next() // ให้ไปทำงานต่อ handler ฟังก์ชั่นในลำดับถัดไป }) // ส่งกลับข้อความ "hello world" เมื่อมี GET request มายังหน้า homepage app.get('/', function (req, res) { console.log(res.myobj) // ทดสอบแสดงค่า ที่เราปรับแต่ง req res.send('hello world ') })
ดูผลลัพธ์
จะเห็นว่าข้อความ “Accessing the secret section …” ซึ่งอยู่ใน middleware function
ที่เรากำหนดเอง แสดงก่อน จากนั้น เราก็ทำการเพิ่ม property เข้าไปใน req object ชื่อ
myobj กำหนดค่า เท่า 1 เสร็จแล้วก็ใช้ฟังก์ชั่น next() เพื่อไปทำคำสั่ง ลำดับถัดไป
ซึ่งก็คือฟังก์ชั่นที่ทำงานเมื่อมี GET Request มาที่ “/” ก็จะแสดง req.myobj ค่าที่เราได้ปรับแต่ง
เพิ่มเติม ถูกส่งเข้ามา และแสดงผลออกทาง console ตามรูป นั่นก็หมายความว่า การดักจับการทำงาน
หรือการแทรกการทำงานด้วย middleware ฟังก์ชั่นข้างต้น สามารถทำงานได้
นอกจาก middleware ที่เรากำหนดแล้ว ยังมี middleware ฟังก์ชั่นอื่นๆ ที่เราสามารถเรียกใช้งานได้
ซึ่งจะได้รู้จักในลำดับต่อๆ ไป
Route paths
เราได้รู้จักเกี่ยวกับ route path บางส่วนไปแล้ว ซึ่งส่วนของ Path เป็นส่วนที่ใช้งานร่วมกับ
request method โดยสามารถกำหนดเป็น
stinrg เช่น “/” , “/about” , “/random.text” เป็นต้น
string pattern เช่น “/ab?cd” , “/ab+cd” , “‘/ab*cd'” เป็นต้น
regular expression เช่น /a/ , /.*fly$/ เป็นต้น
ตัวอักขระ ?, +, * และ () เป็นส่วนหนึ่งของรูปแบบ regular expression
สัญลักษณ์ (-) hyphen และ dot (.) เป็นส่วนหนึ่งของ string
สัญลักษณ์ ($) dollar sign สามารถกำหนดใน path โดยต้องไว้ในในเครื่องหมาย ([ และ ])
ยกตัวอย่าง เช่น เรียกไปที่ path “/data/$book” ต้องกำหนดเป็น “/data/([\$])book”
ตัวอย่างการกำหนด route path ในรูปแบบต่าง
รูปแบบ String
app.get('/', function (req, res) {}) // Root route: / app.get('/about', function (req, res) {}) // route: /about app.get('/random.text', function (req, res) {}) // route: /random.text
รูปแบบ String Pattern
app.get('/ab?cd', function (req, res) {}) // route: /acd และ abcd // เครื่องหมาย ? วางอยู่หลังตัวอักขระใดๆ หมายถึง ตัวนั้นๆจะมี หรือไม่มีก็ได้ app.get('/ab+cd', function (req, res) {}) // route: /abcd และ /abbcd และ /abbbcd...ไปเรื่อยๆ // เครื่องหมาย + วางอยู่หลังตัวอักขระใดๆ หมายถึง ต้องมีตัวนั้นๆ อย่างน้อย 1 หรือก็คือ มี b กี่ตัวก็ได้ app.get('/ab*cd', function (req, res) {}) // route: /abcd, /abxcd, /abRANDOMcd ...ไปเรื่อยๆ // เครื่องหมาย * วางอยู่ตำแหน่งใดๆ เหมือนถึงไม่มี หรือมีตัวอักษระใดๆ ก็ได้ app.get('/ab(cd)?e', function (req, res) {}) // route: /abe และ /abcde // เครื่องหมายวงเล็บใช้จัดกลุ่มของข้อมูล และใช้ร่วมกับเครื่องหมายอื่น ดังนั้นจึงหมายถึง มี cd หรือไม่ก็ได้
รูปแบบ Regular Expression
app.get(/a/, function (req, res) {}) // route: ทุกๆ path ที่มี "a" อยุ่ในนั้น เช่น // route: /about , /contact app.get(/.*fly$/, function (req, res) {}) // route: ทุกๆ path ที่ลงท้ายด้วย fly เช่น // route: /butterfly , /dragonfly
Route parameters
Route parameter หรือเรียกอีกอย่างหนึ่งว่า URL segments เป็นส่วนที่ใช้สำหรับเก็บค่าไว้ในตำแหน่งต่างๆ
ของ URL โดยค่าเหล่านี้ จะถูกเรียกใช้งานผ่าน req.params object กล่าวคือ โดยชื่อของ parameter
จะกำหนดเป็นชื่อ key ในรูปแบบ :[key ชื่อ parameter] เรียงตามลำดับ
Route path: /users/:userId/books/:bookId Request URL: http://localhost:3000/users/34/books/8989 req.params: { "userId": "34", "bookId": "8989" }
สังเกต ชื่อ parameter จาก URL ข้างต้น จะมีด้วยกัน 2 key คือ :userId และ :bookId
ในการกำหนด route path ที่มี route parameter ตามรูปแบบข้างต้น สามารถทได้ดังนี้
app.get('/users/:userId/books/:bookId', function (req, res) { res.send(req.params) })
ชื่อ parameter ต้องกำหนดเป็น ข้อความที่เป็นตัวเลขและตัวอักษรภาษาอังกฤษตามรูปแบบ
([A-Za-z0-9_]) ประกอบด้วยตัวพิมพ์เล็กหรือตัวพิมพ์ใหญ่หรือตัวเลขหรือสัญลักษณ์ _ (underscore)
สำหรับ hyphen (-) และ dot (.) สามารถใช้งานร่วมกับ route parameter เพื่อวัตถุประสงค์พิเศษ
บางอย่างได้ เช่น เชื่อม parameter 2 ตัวด้วย (-) หรือ (.) เข้าด้วยกัน
Route path: /flights/:from-:to Request URL: http://localhost:3000/flights/LAX-SFO req.params: { "from": "LAX", "to": "SFO" }
Route path: /plantae/:genus.:species Request URL: http://localhost:3000/plantae/Prunus.persica req.params: { "genus": "Prunus", "species": "persica" }
นอกจากนั้น เรายังสามารถใช้วงเล็บ () ต่อท้าย parameter ที่เราต้องการกำหนดรูปแบบของข้อมูลที่
จะใช้งานได้ เช่่น (\d+) คือ ต้องมีตัวเลข ตัวอย่างการกำหนดเพิ่มเติม
\d -- ตัวเลขทุกตัว 0 - 9 \D -- ตัวอักขระทุกตัว ยกเว้น เลข 0 - 9 \s -- ช่องว่างทุกตัว \S -- ตัวอักขระทุกตัว ยกเว้นช่องว่าง \w -- ตัวอักษร ตัวเลข ทุกตัว ยกเว้นตัวอักขระพิเศษ . \ + * ? [ ^ ] % $ ( ) { } = ! < > | : - \W -- ตัวขระพิเศษทุกตัว และช่องว่าง ยกเว้น ตัวอักษร และตัวเลข
ซึ่งกรณีมีการใช้งาน \ ใน regular expression ให้เราเพิ่มเป็น \\ เพราะถ้ามีตัวเดียว
จะถูกตีความว่าเป็น string ตัวหนึ่งเท่านั้น ทำให้ไมีมีการแปลงความหมายของค่ากำหนด
กล่าวคือ ถ้ากำหนดเป็น \d จะมอง \ และ d เป็น string ปกติทั่วไป แต่ถ้า กำหนดเป็น \\d
จะตีความหมายและแปลงเป็นเงื่อนไขว่า เป็นตัวเลขทุกตัว 0-9 แบบนี้เป็นต้น
app.get('/users/:userId(\\d+)', function (req, res) { res.send(req.params) })
Route handlers
Route handler หรือก็คือฟังก์ชั่นส่วนที่ทำงานเมื่อเข้าเงื่อนไข หรือ url ที่ผู้ใช้งานเรียกเข้ามา
ตรงกับรูปแบบที่เรากำหนด อย่างที่ได้เข้าใจไปบ้างแล้วในตอนต้นกริ่นนำว่า เราสามารถกำหนดให้ ทำ
ฟังก์ชั่นได้มากกว่า 1 ฟังก์ชั่น โดยใช้ middleware function เข้ามาช่วย โดยมีคำสั่ง next()
เพื่อส่งไปทำงานฟังก์ชั่นที่เหลือ
เราสามารถกำหนด route handler ในรูปแบบของฟังก์ชั่น ,อาเรย์ของฟังก์ชั่น หรือทั้งสองอย่างรวมกันก็ได้
ตัวอย่างด้านล่างเป็นรูปแบบฟังก์ชั่นเดี่ยว ที่เราเห็นตัวอย่างมาบ่อยแล้ว
รูปแบบฟังก์ชั่นเดียว
app.get('/example/a', function (req, res) { res.send('Hello from A!') })
รูปแบบหลายฟังก์ชั่น
app.get('/example/a', function (req, res, next) { req.myobj = 'Hello from A!' next() },function(req, res){ req.myobj += ' Again!!!' res.send(req.myobj) })
ฟังก์ชั่นแรก เรากำหนด req.myobj เท่ากับ ‘Hello from A!’ จากนั้นส่งต่อไปฟังก์ชั่นที่ สอง
โดยเพิ่มคำว่า ‘ Again!!’ เข้าไป เสร็จแล้ว ส่งออกไปแสดงหน้าบราวเซอร์ จะได้ผลลัพธ์ดังรูป
รูปแบบ array ของฟังก์ชั่น
var func_a = function(req, res, next) { req.myobj = 'A' next(); } var func_b = function(req, res, next) { req.myobj += ' B' next(); } var func_c = function(req, res) { req.myobj += ' C' res.send(req.myobj); } app.get('/example/a', [func_a,func_b,func_c])
รูปแบบผสมหลายแบบ
var func_a = function(req, res, next) { req.myobj = 'A' next(); } var func_b = function(req, res, next) { req.myobj += ' B' next(); } app.get('/example/a', [func_a,func_b],function (req, res, next){ req.myobj += ' C' next(); },function(req, res){ req.myobj += ' D' res.send(req.myobj); });
Response methods
ใน response นั้น (res – response object) จะมี method ที่ทำหน้าที่ส่งกลับข้อมูลมายังผู้ใช้งาน และสิ้นสุดการทำงาน
ของกระบวนการ request response ที่เกิดขึ้น ซึ่งถ้าไม่มีการใช้งาน method ในส่วนนี้ การ request จากฝั่งผู้ใช้ อาจจะ
มีอาการค้างหรือหยุดการทำงานไป
รายการ response method ที่ใช้บ่อย ประกอบไปด้วย
res.download()
ทำการดาวน์โหลดไฟล์ที่ต้องการ
res.download('/report-12345.pdf'); res.download('/report-12345.pdf', 'report.pdf'); res.download('/report-12345.pdf', 'report.pdf', function(err){ if (err) { // อาจจะส่งข้อความแจ้งว่า ดาวน์โหลดไม่สำเร็จ หรืออื่นๆ โดยใช้ res.send() } else { // ทำคำสั่งอื่นๆ เช่น นับจำนวนการดาวน์โหลด } });
// ตัวอย่างดาวน์โหลดโฟล์ app.js2 ซึ่งไม่มีไฟล์ดังกล่าง เป็นชื่อ mysavefile.txt app.get('/download',function(req, res){ res.download('app.js2','mysavefile.txt',function(err){ if (err) { // console.log(res.headersSent) console.log(err) console.log("Can't downlaod") res.send("Can't download file!") } else { console.log("file downloaed") } }) })
res.end()
จบการทำงาน โดยไม่ส่งค่าใดๆ กลับ
res.end(); res.status(404).end();
res.json()
ส่งกลับข้อมูลในรูปแบบ JSON string
res.json(null); res.json({ user: 'tobi' }); res.status(500).json({ error: 'message' });
res.jsonp()
ส่งกลับข้อมูลในรูปแบบ JSON string รองรับ JSONP
res.jsonp(null); // => callback(null) res.jsonp({ user: 'tobi' }); // => callback({ "user": "tobi" }) res.status(500).jsonp({ error: 'message' }); // => callback({ "error": "message" }) // ?callback=foo res.jsonp({ user: 'tobi' }); // => foo({ "user": "tobi" }) // กรณีกำหนด callback name เป็นชื่ออื่น app.set('jsonp callback name', 'cb'); // ?cb=foo res.status(500).jsonp({ error: 'message' }); // => foo({ "error": "message" })
res.redirect()
ลิ้งค์หรือเปลี่ยน path ไปยัง url ที่กำหนด เช่น
res.redirect('/foo/bar'); res.redirect('http://example.com'); res.redirect(301, 'http://example.com'); res.redirect('../login'); res.redirect('..'); // การย้อนกลับมา 1 path res.redirect('back'); // การย้อนกลับไป path ก่อนหน้า
res.render()
สร้าง HTML string จาก view template แล้วส่งออกมาแสดง เราจะได้ศึกษาเพิ่มเติม เกี่ยวกับ view template
res.send()
ส่งข้อมูลกลับมาแสดง โดยสามารถเป็น Buffer Object , String ข้อความ , Object และ Array เช่น
res.send(new Buffer('whoop')); res.send({ some: 'json' }); res.send('<p>some html</p>'); res.send([1,2,3]); res.status(404).send('Sorry, we cannot find that!'); res.status(500).send({ error: 'something blew up' });
res.sendFile()
ส่งไฟล์ หรือนำข้อมูลไฟล์มาแสดง Send a file as an octet stream
app.get('/about',function(req, res){ // ตัวอย่งแสดงไฟล์ about.html ที่อยู่ใน root // ซึ่งเวลาใช้งานจริง เราจะใช้ path module มาข่วย จะไม่กำหนดลักษณะนี้ // res.sendFile(path.join(__dirname+'/about.html')); // กรณีใช้ path module res.sendFile("C:\\projects\\expressjs\\about.html") })
res.sendStatus()
กำหนด status code และ ส่งข้อความแจ้ง เช่น
res.sendStatus(200); // มีค่าเท่ากับใช้คำสั่ง res.status(200).send('OK') res.sendStatus(403); // มีค่าเท่ากับใช้คำสั่ง res.status(403).send('Forbidden') res.sendStatus(404); // มีค่าเท่ากับใช้คำสั่ง res.status(404).send('Not Found') res.sendStatus(500); // มีค่าเท่ากับใช้คำสั่ง res.status(500).send('Internal Server Error')
ข้างต้น เป็น response method ที่เราจะได้เจอบ่อยๆ ในการใช้งาน express ยังมี method อื่นๆ อีก
รวมถึง method ที่กล่าวมายังมีรายละเอียด ที่เราต้องศึกษาเพิ่มเติมในลำดับต่อๆ ไป
app.route()
เราสามารถเชื่อมการทำงานให้กับ route เป็นฟังก์ชั่นต่อๆ กัน หรือที่เรียกว่า chain โดยการใช้งาน app.route()
ซึ่งจะช่วยลดขั้นตอนที่ซับซ้อนและป้องกันความผิดพลาดในการพิมพ์ เพราะบางครั้ง เรามีการกำหนด route path
ซ้ำๆ กันให้กับ method ต่างๆ ดังนั้น การกำหนด route path ที่เดียว แล้วกำหนด method แยกย่อยลงไป จะทำให้
ลดขั้นตอนการเขียนลงได้ ตามตัวอย่างด้านล่าง
app.route('/book') .get(function (req, res) { res.send('Get a random book') }) .post(function (req, res) { res.send('Add a book') }) .put(function (req, res) { res.send('Update the book') })
express.Router
ในการพัฒนา web app ที่มีความซับซ้อนหรือมีโครงสร้างการทำงานจำนวนมาก การกำหนด route path ไว้ในไฟล์ app.js
คงไม่ใช่วิธีที่ถูกต้องหรือเหมาะสม การสร้างไฟล์แยกเป็นอีก module หรือก็คือการสร้าง mini-app แยกย่อย แล้วค่อยนำมา
เรียกใช้งานในไฟล์หลัก จึงเป็นวิธีที่เหมาะสมที่ถูกนำมาใช้งาน
โดยเราสามารถใช้ express.Router class เพื่อสร้าง module หรือสร้างไฟล์ module ใหม่ ที่สามารถเชื่อมกับการจัดการ
ของฟังก์ชั่นใน route ตัว Router ที่เป็น instance ของ expressRouter ก็คือ middleware ตัวหนึ่งที่เราสามารถเรียกใช้งาน
ในไฟล์หลัก
ทดสอบ เพื่อทำควาเข้าไจ ตามลำดับดังนี้
ให้เราสร้างไฟล์ birds.js ไว้ใน root โฟลเดอร์ ที่เดียวกับ app.js แล้วกำหนดโค้ดตามตัวอย่างด้านล่าง
var express = require('express') // เรียกใช้งาน express mudule var router = express.Router() // กำหนด router instance ให้กับ express.Router class // เราใช้คำสั่ง use() เพื่อเรียกใช้งาน middleware function // middleware ที่กำงานใน router instance ก่อนเข้าไปทำงานใน route function router.use(function timeLog (req, res, next) { console.log('Time: ', Date.now()) next() }) // กำหนด route หลัก หรือ root route router.get('/', function (req, res) { res.send('Birds home page') }) // กำหนด route เพิ่มเติม router.get('/about', function (req, res) { res.send('About birds') }) module.exports = router // ส่ง router ที่เราสร้าง ออกไปใช้งานภายนอกไฟล์
จากนั้นมาที่ไฟล์ app.js เราจะทำการโหลด router module จากไฟล์ birds.js ที่เราสร้างมาใช้งาน โดยทำได้ดังนี้
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const port = 3000 // port const birds = require('./birds') // ใช้งาน router module // เรีรยกใช้งานในรูปแบบ middlewar โดยใช้ use app.use('/birds', birds) // ส่งกลับข้อความ "hello world" เมื่อมี GET request มายังหน้า homepage app.get('/', function (req, res) { res.send('hello world ') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
จะเห็นว่า เราสามารถกำหนด กี่ module เข้ามาก็ได้ โดยใช้ use()
ถ้าเราสังเกตดีๆ จะพบว่า ในไฟล์ app.js มีการกำหนด route path ของหน้าแรก app ไว้แล้ว คือให้แสดง hello world
แล้วทำไมในไฟล์ birds จึงมีการกำหนด root route path เหมือนกัน แล้ว จะมีการเรียกไปที่ path ไหนเมื่อเข้าหน้าแรก
คำตอบคือ ให้สังเกตจากการกำหนด path ของ router module ที่เราเรีรยกใช้ เรากำหนดเป็น
app.use('/birds', birds)
นั่นหมายความว่า router.get(‘/’) ในไฟล์ birds.js จึงหมายถึง path: /birds
และ router.get(‘/about’) ในไฟล์ birds.js จึงหมายถึง path: /birds/about
แล้วถ้าเราเปลี่ยนหน้า app.js เป็น
app.use('/', birds)
ลักษณะแบบนี้ คือเป็นการเปลี่ยน route path หลักไปที่ birds module ดังนั้น เมื่อเข้าหน้าแรก
จึงเข้าไปทำงานในไฟล์ birds.js แทน และไม่แสดงคำว่า hello worldl
ดูตัวอย่างผลลัพธ์ประกอบ
สมมติเราเปลี่ยนเป็น app.use(‘/’, birds) ก็จะได้หน้าแรกเป็นดังนี้
ในเนื้อหาตอนนี้ เราได้เข้าใจส่วนต่างๆ ของ Routing ไปพอสมควรแล้ว หวังว่าจะเป็นแนวทาง
สำหรับทำความเข้าใจในส่วนอื่นๆ เพิ่มเติมต่อไป
[Update] รู้จักับ Middleware ฟังก์ชั่น ใน Express และการใช้งานเบื้องต คอร์สเรียน เรียนฟรี ออนไลน์ บทความ | การใช้ use – NATAVIGUIDES
Middleware ฟังก์ชั่น คืออะไร
Middleware ฟังก์ชั่น คือ ฟังก์ชั่นที่สามารถเข้าไปจัดการกับ
request object (req) , response object (res) และ ฟังก์ชั่น next()
ที่อยู่กระบวนการเกิดของ request-response cycle
next ฟังก์ชั่น คือฟังก์ชั่นที่อยู่ใน express router ซึ่งเมื่อมีการเรียกใช้งาน จะเป็น
การไปทำงานใน middleware ฟังก์ชั่นในลำดับถัดไป จากฟังก์ชั่นปัจจุบัน
มาดูส่วนที่เรียกว่า middleware ฟักง์ชั่นจากโค้ดตัวอย่างต่อไปนี้
Middleware ฟังก์ชั่น ทำหน้าที่ต่างๆ ดังนี้
- รันคำสั่งต่างๆ ที่กำหนด
- แก้ไขข้อมูลของ request / response object
- จบการทำงาน request-response cycle
- ใช้งานคำสั่ง next เพื่อทำงาน middleware ฟังก์ชั่นถัดไป
ถ้ายังไม่จบการทำงานใน middleware ฟังก์ชั่นปัจจุบัน จะต้องใช้คำสั่ง next() เพื่อส่งต่อ
ไปทำงานในฟังก์ชั่นต่อไป ไม่เช่นนั้น การ request หรือร้องขอข้อมูลก็อาจจะค้าง ไม่สามารถทำงานต่อได้
Request – Response cycle
ลักษณะการทำงานหรือกระบวนการเกิดของ request-response cycle ก็คือ
- ผู้ใช้เปิดบราวเซอร์ พิมพ์ URL ที่ต้องการ แล้วกด Enter
- ตัวบราวเซอร์จะทำการ request หรือร้องขอไปยัง Server ผ่าน URL ที่กำหนด
- เมื่อ request ที่ส่งมายัง Server ตรงกับ Route หรือ URL Path ที่กำหนดการทำงานเอาไว้ ก็จะทำงาน
- เมื่อทำงานเสร็จ ก็จะ response ส่งต่อค่าต่างๆ กลับมายังส่วนของการแสดงผล
- โดยอาจทำการ render หรือสร้างเป็นรูปแบบ HTML แล้วส่งกลับมายังบราวเซอร์
- เมื่อเพจโหลดเสร็จเรียบร้อย ผู้ใช้ก็จะเห็นหน้าตาเพจ แสดงข้อมูลที่ถูกส่งกลับมา
ประเภทของ Middleware ฟังก์ชั่น
- Application-level middleware
- Router-level middleware
- Error-handling middleware
- Built-in middleware
- Third-party middleware
ในกรณีใช้งาน Application-level และ Router-level เราสามารถกำหนด Path ให้กับ middleware
ฟังก์ชั่นนั้นๆ ได้ รวมทั้งยังสามารถเรียกใช้งาน middleware ฟังก์ชั่นแบบรวมชุดฟังก์ชั่นไปพร้อมๆ กันได้
เราจะมาทำความรู้จักเพิ่มเติมในแต่ละประเภทตามลำดับ ดังนี้
Application-level middleware
Middleware ฟังก์ชั่นในระดับ Application-level เป็นฟังก์ชั่นที่เรียกใช้งานผ่าน app object โดยใช้คำสั่ง
app.use() และ app.METHOD() โดยที่คำว่า METHOD ก็คือ HTTP method เช่น get post put หรือ delete
เหล่านี้เป็นต้น ตัวอย่างเช่น app.get() app.post() app.put() หรือ app.delete()
ตัวอย่างด้านล่าง เป็นโค้ดตัวอย่างการใช้งาน middleware ฟังก์ชั่น ที่ไม่ได้มีการระบุ path ซึ่งฟังก์ชั่นดังกล่าว
จะทำงานทุกๆ ครั้ง ที่ app มี request เข้ามา
const app = express() // app object ใช้คำสั่ง use() เรียกใช้งานฟังก์ชั่นด้านใน ซึ่งเรียกว่า middleware function app.use(function (req, res, next) { console.log('Time:', Date.now()) // ส่วนนี้จะทำงานทุกครั้งเมื่อมี request เข้ามา next() })
ต่อไปมาดู middleware ฟังก์ชั่น ที่มีการระบุ path: “/user/:id” โดยจะทำให้ฟังก์ชั่นนี้ ทำงานในกรณีที่มีการ
request มาที่ URL path: “/user/:id” เท่านั้น
// app object ใช้งาน middleware ฟังก์ชั่น แบบมีการระบุ path app.use('/user/:id', function (req, res, next) { console.log('Request Type:', req.method) next() })
ต่อด้วย middleware ฟังก์ชั่น ที่ใช้งานผ่าน app.METHOD โดยมีการกำหนด route path และใช้ Request
method แบบ GET มายัง path: “/user/:id”
// app object ใช้งาน middleware ฟังก์ชั่นผ่าน app.METHOD โดยมีการระบุ path app.get('/user/:id', function (req, res, next) { res.send('USER') // เมื่อใดก็ตามที่มีการใช้คำสั่ง send() แสดงว่าเป็นการจบการทำงานของ // request - reponse cycle })
ต่อไปมาดูตัวอย่าง การเรียกใช้งาน middleware ฟังก์ชั่นแบบมาเป็นชุดฟังก์ชั่น หลายตัวพร้อมกัน
โดยไล่ลำดับการทำงานไปตามลำดับก่อนหลัง
app.use('/user/:id', function (req, res, next) { // ทำงาน ฟังก์ชั่นนี้เสร็จ console.log('Request URL:', req.originalUrl) next() // ส่งไปทำงานต่อในฟังก์ชั่น ตัวถัดไป }, function (req, res, next) { // ทำงานต่อที่ฟังก์ชั่นนี้ console.log('Request Type:', req.method) next() //ส่งไปทำงาน middleware ฟังก์ชั่นอื่นๆ ในลำดับถัดไปต่อ })
เราสามารถใช้งาน app.METHOD กำหนด route path หลายอันซ้ำกัน ได้ ต้วอย่างด้านล่าง เรากำหนด
route path ให้กับ GET request สองตัว ที่มี route path เหมือนกัน คือชี้ไปที่ path: “/user/:id”
ซึ่งเมื่อเรียกใช้งาน ตัว route path ตัวที่สอง ถึงจะไม่มีข้อผิดพลาดใดๆ เกิดขึ้น แต่ มันก็ไม่ทำงาน ทั้งนี้ก็
เพราะว่า ใน route path ตัวแรก มีการ ใช้คำสั่ง send() ซึ่งเป็นการจบการทำงานของ request-response
cycle ด้วยการส่งข้อความคำว่า “User Info” ออกมาแสดง
// เรียกไปยัง path: /user/:id และทำงาน middelware ฟังก์ชั่นที่ซ้อนกันตามลำดับ app.get('/user/:id', function (req, res, next) { console.log('ID:', req.params.id) next() }, function (req, res, next) { res.send('User Info') // เมื่อใดก็ตามที่มีการใช้คำสั่ง send() แสดงว่าเป็นการจบการทำงานของ // request - reponse cycle }) // เรียกไปยัง path: เดิม /user/:id อีกครั้ง แต่ ก็ไม่ทำงาน app.get('/user/:id', function (req, res, next) { res.end(req.params.id) })
อย่างไรก็ตาม เพื่อข้าม middleware ฟังก์ชั่นที่ซ้อนๆ กัน เราสามารถใช้คำสั่ง next(‘route’) เพื่อไปทำงาน
ใน route path ลำดับถัดไปที่มี path ซ้ำกัน ได้ โดยข้าม middleware ฟังก์ชั่นอื่น ที่ซ้อนอยู่ ดูตัวอย่าง
โค้ดด้านล่างประกอบ
// เรียกไปยัง path: /user/:id และทำงาน middelware ฟังก์ชั่นที่ซ้อนกันตามลำดับ app.get('/user/:id', function (req, res, next) { // ทำการตรวจสอบเงื่อนไข ว่า user ID เท่ากับ 0 หรือไม่ ถ้าเท่ากับ 0 ที่ก็ข้าม ฟังก์ชั่นที่ซ้อนอยุ่ไป // แล้วออกไปทำงานที่ route path ที่กำหนดซ้ำกัน ในลำดับถัดไป if (req.params.id === '0') next('route') // โดยใช้คำสั่ง next('route') // กรณีที่ไม่เท่ากับ 0 ก็ทำงาน middleware function ที่ซ้อนกันอยู่ในลำดับถัดไปตามลำดับ else next() // โดยใช้คำสั่ง next() }, function (req, res, next) { res.send('regular') // เมื่อใดก็ตามที่มีการใช้คำสั่ง send() แสดงว่าเป็นการจบการทำงานของ // request - reponse cycle }) // เรียกไปยัง path: เดิม /user/:id อีกครั้ง จะทำงาน เมื่อถูกเรียกผ่านคำส่ัง next('route') // จาก middleware ฟังก์ชั่นก่อนหน้า app.get('/user/:id', function (req, res, next) { res.send('special') })
ข้อควรจำ
จำไว้เสมอว่า การใช้งาน next(‘route’) จะสามารถเรียกใช้งานผ่านคำสั่ง app.METHOD() และ
router.METHOD() เท่านั้น ไม่สามารถใช้งานผ่าน app.use() หรือ router.use() ได้
นอกจากการกำหนด middleware แบบซ้อนกันตามลำดับข้างต้นแล้ว เรายังสามารถกำหนดฟังก์ชั่นไว้ในตัวแปร
array เพื่อให้สามารถนำไปใช้งานซ้ำเมื่อต้องการได้ ซึ่งแนวทางลักษณะนี้เรา ได้รู้มาบ้างแล้วใน
หัวข้อ Route handler ของบทความ http://niik.in/908
// mddleware ฟังก์ชั่น 1 function logOriginalUrl (req, res, next) { console.log('Request URL:', req.originalUrl) next() } // mddleware ฟังก์ชั่น 2 function logMethod(req, res, next) { console.log('Request Type:', req.method) next() } // นำ mddleware ฟังก์ชั่น ทั้ง สอง มาเก็บไว้ใน array แล้วเรียกใช้งาน // โดยฟังก์ชั่น จะไล่ทำงานตำลำดับก่อนหลัง ของการกำหนดใน array var logStuff = [logOriginalUrl, logMethod] app.get('/user/:id', logStuff, function (req, res, next) { res.send('User Info') })
Router-level middleware
Middleware ฟังก์ชั่น ในระดับ Router-level มีรูปแบบการใช้งานเหมือนกับในระดับ Application-level
ซึ่ง router ก็คือ app ย่อยตัวหนึ่ง เพียงแต่ว่า router เป็น instance ของ express.Router()
ส่วน app เป็น instance ของ express() ซึ่งเป็น Top-level ฟังก์ชั่น
var router = express.Router() // กำหนด router เป็น instance ของ express.Router() // instance ก็คือต้วแทน เช่น John เป็น instance ของ People
เราสามารถใช้งาน middleware ในระดับ router-level โดยใช้คำสั่ง router.use() และ router.METHOD()
ปกติ เราจะสร้าง router แยกไว้อีกไฟล์ โดยมีการ export เป็น module จากนั้น เราก็เรียกใช้งานผ่านคำสั่ง
app.use() ในไฟล์ app.js หลัก ตามที่เคยผ่านตามาแล้วในบทความที่ผ่านๆ มา
ตัวอย่างโค้ดบางส่วน
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const birds = require('./birds') // ใช้งาน router module // birds ก็เป็น middleware function ที่สร้างจาก exprees.Router() method app.use('/birds', birds)
ตัวอย่างโค้ดด้านล่าง เราจะแสดงให้เห็นถึงการใช้งานของ middleware router-level ซึ่งอยู่ด้านบน ของ
ส่วนการใช้งาน application-level
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const router = express.Router() // ใช้งาน middleware router-level แบบไม่ระบุ path ซึ่งจะทำงานทุกครั้งเมื่อมีการเรียกใช้งาน router router.use(function (req, res, next) { console.log('Time:', Date.now()) next() }) // ใช้งาน middleware router-level แบบซ้อนกันตามลำดับ ผ่านคำสั่ง router.use() โดยมีการระบุ path: "/user/:id" router.use('/user/:id', function (req, res, next) { console.log('Request URL:', req.originalUrl) next() }, function (req, res, next) { console.log('Request Type:', req.method) next() }) // ใช้งาน middleware router-level แบบซ้อนกันตามลำดับ ผ่านคำสั่ง router.METHOD() โดยมีการระบุ path: "/user/:id" router.get('/user/:id', function (req, res, next) { // เช็คเงื่อนไขถ้า user ID เท่ากับ 0 ให้ไแทำงานใน router ของ path เดียวกัน ในลำดับที่อยู่ถัดไป if (req.params.id === '0') next('route') // หากไม่เท่ากับ 0 ให้ไปทำ middleware ในดำดับถัดไปที่ซ้อนกันอยู่ตามลำดับ else next() }, function (req, res, next) { res.render('regular') // เมื่อใดก็ตามที่มีการใช้คำสั่ง render() เพื่อสร้างหน้าผล แสดงว่าเป็นการจบการทำงานของ // request - reponse cycle }) // ทำงาน เมื่อถูกเรียกใช้ผ่าน next('route') router.get('/user/:id', function (req, res, next) { console.log(req.params.id) res.render('special') // เมื่อใดก็ตามที่มีการใช้คำสั่ง render() เพื่อสร้างหน้าผล แสดงว่าเป็นการจบการทำงานของ // request - reponse cycle }) // ส่วนของการใช้งาน middleware applicaiton-level // กำหนด path การเรียกใช้งาน router ให้กับ app app.use('/', router)
ตัวอย่างด้านบน เป็นการสร้าง router ไว้ในไฟล์ app หลัก แล้วเรียกใช้งาน จะเห็นว่ารูปแบบการใช้งานการ
กำหนด middleware ของ router-level จะคล้ายกับรูปแบบของ application-level
เราสามารถใช้คำสั่ง next(‘router’) เพื่อออกจาก router instance แล้วไปทำงาน middleware ฟังก์ชั่นของ
app ที่อยู่นอก router นั้นๆ ในลำดับถัดไป ยกตัวอย่างเช่น ระบบ admin
const app = express() const router = express.Router() // กำหนดการทำงานของ router เมื่อถูกเรียกใช้งาน router.use(function (req, res, next) { // ตรวจสอบเงื่อนไขว่ามีการส่ง req.headers['x-auth'] มาหรือไม่ if (!req.headers['x-auth']) return next('router') // ถ้าไม่มี ให้ออกจาก router แล้วไปทำคำสั่งนอก router ต่อ next() // แต่ถ้ามี ก็ทำคำสั่งใน router ในลำดับถัดไปต่อ }) // router path root ของหน้า "/admin" router.get('/', function (req, res) { res.send('hello, user!') }) // เรียกใช้งาน router ผ่าน path: "/admin หรือกรณีไม่ผ่านเงื่อนไข ก็ทำคำสั่ง ส่ง status 401 ออกมา app.use('/admin', router, function (req, res) { res.sendStatus(401) // 401 UNAUTHORIZED ไม่ได้รับสิทธิ์หรืออนุญาตให้เข้าใช้งาน })
จากโค้ดด้านบน จะเห็นว่า ถึงแม้เรากำหนด router ไว้ก่อนด้านบน แต่เนื่องจาก router เป็น middleware
ฟังก์ชั่นหนึ่ง ดังนั้น การกำหนดในลักษณะข้างต้น ตัว router จะยังไม่ทำงาน แต่จะทำงานเมื่อมีการเรียกใช้
หรือก็คือ มาเริ่มทำงานที่บรรทัด ที่ใช้คำสั่ง app.use()
จะขอลำดับการทำงานตามโค้ดด้วยรูปภาพ กำกับด้วยลำดับตัวเลข และลูกศร ตามรูปด้านล่าง
พร้อมอธิบายในส่วนท้าย
(1)
เมื่อผู้ใช้ เรียกมายัง path: “/admin ก็จะไปเรียก
(2)
router ที่เป็น middleware ฟังก์ชั่น
เมื่อเข้ามาในส่วนของ
(3)
router ก็จะทำการตรวจสอบ เบืองต้นว่า มีการส่ง req.header[‘x-auth’] ค่านี้มาหรือไม่
เพื่อตรวจสอบและยืนยันว่าสามารถเรียกใช้งานผ่าน path นี้ได้ ซึ่งเงื่อนไขตรวจสอบว่า ถ้าไม่มีส่งเข้ามา
ก็จะใช้
(4 กรณีไม่พบค่า)
return คำสั่ง next(‘router’) เพื่อออกจาก router โดยไม่สนคำสั่งในลำดับถัดไปใน router
แล้วไปทำงาน ฟังก์ชั่น ที่อยู่นอก router ในลำดับถัดไปต่อ ซึ่งก็คือทำคำสั่ง ส่งสถานะ เป็น 401
ออกมาด้วยคำสั่ง res.sendStatus(401)
แต่ถ้ามีการส่ง
(4 กรณีพบค่า)
req.header[‘x-auth’] เข้ามาใน router ก็จะไปทำงานคำสั่ง ที่อยู่ภายใน router ต่อโดย
เรียกผ่านคำสั่ง next() ซึ่งก็จะทำการส่งข้อความ “hello, user!” แสดงออกมาแล้วจบการทำงาน
Error-handling middleware
ใน error-handling middleware จะมี arguments ด้วยกันทั้งหมด 4 ตัว คือมีตัวที่ชื่อว่า err (error) เพิ่มเข้ามา
ซึ่งในการกำหนด middleware ในรูปแบบนี้ เราต้องใช้งาน ทั้ง 4 ค่าเสมอ ถึงแม้ว่า เราอาจจะไม่จำเป็นต้องใช้งาน next
ทั้งนี้ก็เพื่อให้คงรูปแบบการใช้งานที่ถูกต้อง ไม่เช่นนั้นแล้ว มันจะถูกตีความหมายว่าเป็น middleware ฟังก์ชั่นปกติ
ทำให้ไม่สามารถจัดการข้อผิดพลาดต่างๆ ได้
ตัวอย่างโค้ดด้านล่าง เป็นรูปแบบการใช้งาน error-handling middleware ฟังก์ชั่น
app.use(function (err, req, res, next) { console.error(err.stack) res.status(500).send('Something broke!') })
ทั้งนี้ เราอาจจะได้ศึกษารายละเอียดเพิ่มเติม เกี่ยวกับ error-handling middleware ในลำดับต่อๆ ไป
Built-in middleware
เป็น middleware ฟังก์ชั่น ที่อำนวยความสะดวกให้กับการพัฒนา express app ซึ่งเราได้รู้จักไปแล้วในหัวข้อที่ผ่านมา
ตัวอย่างเช่น
- express.static() // เรียกใช้งาน static file เช่น ไฟล์รูปภาพ ไฟล์ js ไฟล์ css เป็นต้น
- express.json() // แปลงข้อมูลที่มีรูปแบบ JSON String ให้อยู่ในรูป JSON Objext
- express.urlencoded() // แปลงข้อมูลจาก form ในรูปแบบ url encode เป็น Object
Third-party middleware
เป็น middleware ฟังก์ชั่น ที่มีผู้พัฒนาแยกเป็น package ไว้ ไม่ได้อยู่ใน Express app โดยเราสามารถทำการติดตั้ง
ผ่าน ตัวจัดการ package ของ NodeJs หรือที่เรียกว่า mpm (Node Package Manager)
ตัวอย่างด้านล่าง เป็นวิธีการติดตั้ง “cookie-parser” ซึ่งเป็น Third-party middleware ที่มีฟังก์ชั่นและเครื่องมือต่างๆ
ให้เราเรียกใช้งาน ในการจัดการกับ Cookies
npm install cookie-parser
เมื่อติดตั้งเรียบร้อยแล้ว เราสามารถเรียกใช้งานในรูปแบบ application-level หรือ router-level ก็ได้
ตัวอย่างโค้ดการเรียกใช้งาน แบบ application-level
const express = require('express') const app = express() const cookieParser = require('cookie-parser') // เรียกใช้งาน cookie-parsing middleware app.use(cookieParser())
การสร้าง Middleware ฟังก์ชั่น
เมื่อเราได้รู้จักประเภทต่างๆ ของ middleware ฟังก์ชั่นไปพอสมควรบ้างแล้ว เนื้อหาในหัวข้อนี้ เราจะทำการ
สร้าง middleware ฟังก์ชั่น สำหรับใช้งานใน Express app ของเรา ซึ่งเป็นแนวทางอย่างง่าย เบื้องต้น
สมมติเราเริ่มต้นที่ตัวอย่าง “Hello World” Express app อย่างง่ายตามโค้ดดังนี้
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const port = 3000 // port app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
ต่อไปเราสร้าง middleware ฟังก์ชั่นที่ชื่อ myLogger โดยการทำงานของฟังก์ชั่นนี้ก็คือพิมพ์คำว่า
“LOGGED” เมื่อเกิด request มายัง app ในที่นี้เรากำหนดชื่อตัวแปรให้กับ middleware ฟังก์ชั่นเป็น
myLogger จะได้เป็น
const myLogger = function (req, res, next) { console.log('LOGGED') next() }
ในการใช้งาน middleware ฟังก์ชั่นเราใช้คำส่ง app.use() เพื่อกำหนดฟังก์ชั่นที่จะใช้งาน จะได้เป็น
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const port = 3000 // port const myLogger = function (req, res, next) { console.log('LOGGED') next() } app.use(myLogger) app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
เมื่อทดสอบรัน app จะพบว่า ทุกครั้งที่มี request เกิดขึ้น ก็จะพิมพ์คำว่า “LOGGED” ออกมา
ทาง terminal (
* อย่าลืมว่า NodeJs ทำงานที่ฝั่ง server การใช้คำสั่ง console.log() ใน NodeJs App
จะหมายถึง การแสดงข้อมูลทาง terminal หรือ command line ฝั่ง server
)
ในการเรียกใช้งาน middleware ฟังก์ชั่น นั้น การวางตำแหน่งลำดับของ middleware ฟังก์ชั่นใดๆ
จะหมายถึงการเรียกลำดับก่อนหลัง นั่นคือ ถ้ากำหนดให้เรียกใช้ middleware ฟังก์ชั่นใดก่อน ก็จะทำงาน
ก่อนเสมอ เป็นต้น
ดูลำดับการทำงานตามรูปภาพประกอบด้านล่าง
Middleware ฟังก์ชั่น Module
ถ้าเราต้องการสร้าง middleware ฟังก์ชั่น ที่สามารถตั้งค่าหรือกำหนด option ค่าต่างๆ เพิ่มเติมได้
เราสามารถสร้าง middleware ฟังก์ชั่น เป็น module แยกเป็นอีกไฟล์ แล้วเรียกใช้งาน ซึ่งสามารถทำได้
ดังนี้
สมมติเราใช้ชื่อไฟล์ว่า my-logger.js
module.exports = function(options) { return function(req, res, next) { console.log(options.message) next() } }
จากนั้นเรียกใช้งาน module ด้วยคำสั่ง require() ในไฟล์ app.js ดังนี้
const express = require('express') // ใช้งาน module express const app = express() // สร้างตัวแปร app เป็น instance ของ express const port = 3000 // port const myLogger = require('./my-logger') app.use(myLogger({message:"LOGGED MESSAGE"})) app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(port, function() { console.log(`Example app listening on port ${port}!`) })
สังเกตว่า เราสามารถเรียกใช้งาน middleware ฟังก์ชั่น โดยรองรับการตั้งค่าเพิ่มเติมได้
อย่างในตัวอย่างด้านบน เราส่งข้อความใดๆ ก็ได้ไปใช้งานในฟังก์ชั่น myLogger()
เนื้อหาทั้งหมดในตอนนี้ เราก็ได้ทำความรู้จักเกี่ยวกับ middleware ฟังก์ชั่น เพิ่มขึ้น เพื่อเป็น
แนวทางในการประยุกต์ใช่ต่อไป
SQUID GAME CHALLENGE || Impossible Acrobatics Test only 1% of Players Can Do by 123 GO! CHALLENGE
How is this even possible?
Let’s try som Brand New Acrobatic Flexibility Challenge.
What Tik Tok trend is your favourite to try with friends? Let us know in the comments below. And don’t forget to subscribe to our channel for more videos just like this one.
challenge 123go acrobatics tiktok
Music by Epidemic Sound: https://www.epidemicsound.com/
Stock materials: https://www.depositphotos.com https://www.shutterstock.com
This video is made for entertainment purposes. We do not make any warranties about the completeness, safety and reliability. Any action you take upon the information on this video is strictly at your own risk, and we will not be liable for any damages or losses. It is the viewer’s responsibility to use judgment, care and precautions if one plans to replicate.
The following video might feature activity performed by our actors within controlled environment please use judgment, care, and precaution if you plan to replicate.
All product and company names shown in the video are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
นอกจากการดูบทความนี้แล้ว คุณยังสามารถดูข้อมูลที่เป็นประโยชน์อื่นๆ อีกมากมายที่เราให้ไว้ที่นี่: ดูเพิ่มเติม
การใช้ used to, be used to, get used to | Eng ลั่น [by We Mahidol]
used to, be used to และ get used to เป็นคำที่เหมือนจะคล้ายกันมาก หลายคนจึงใช้สลับไปลสับมา แต่จริง ๆ แล้ว ทั้ง 3 คำนี้ มีลักษณะการใช้งานที่แตกต่างกัน ถ้าอยากรู้ว่าแต่ละคำใช้งานอย่างไร ตามพี่คะน้าไปดูเลย
Learn WithMe Engลั่น WeMahidol Mahidol usedto beusedto getusedto
YouTube : We Mahidol
Facebook : http://www.facebook.com/wemahidol
Instagram : https://www.instagram.com/wemahidol/
Twitter : https://twitter.com/wemahidol
มหาวิทยาลัย มหิดล Mahidol University : https://www.mahidol.ac.th/th/
Website : https://channel.mahidol.ac.th/
Difference Between Used To and Would
Practice the grammar from this video in the special MINICOURSE on my website https://nmodel.net/courses/usedto_would
Both \”used to\” and \”would\” are about some things of the past that no longer happen or exist. Is there any difference between the two forms in meaning? Yes, sometimes there is! Watch this video and find out!
📙Category: English grammar
👨🎓Level: Preintermediate (B1)
📄Contents:
0:09 \”used to\” and \”would\” for regular/habitual actions in the past
1:03 forms of \”used to\”: affirmative, negative and questions
1:27 forms of \”would\”: affirmative, negative, questions
1:51 \”used to\” for permanent actions in the past
2:43 \”used to\” for permanent states in the past (with stative verbs)
3:54 \”would\” with temporary states (with frequency adverbs: sometimes, often, usually)
✏️Write your examples and questions in the comments, and we will practise together!
english usedto would alexeikiselev английский
How to use cutter strap leather diy.สอนการใช้งานคับ
สอนการใช้งานตัวตัดหนังเส้นงานdiy
www.etsy.com/shop/surakanleather
$6500 profits using easy strategy | best pocket option strategy
$6500 profits using easy strategy | best pocket option strategy
Hello, my name is Katie and you are on the channel Katie tutorials. Today’s video has a special strategy as this method consists of three simple indicators and can have a big impact on market actions. It is very easy to use and at the same time very effective. In the strategy I use two Moving Average with different periods and Parabolic sar also with different periods. I set the candles for 30 seconds and trade at 1 minute intervals.
Platform Link: https://bit.ly/3hnDHCM
For bonus 50% use promo code: 50START
My Official Telegram Channel: https://t.me/katietutorialsofficial
Friends, remember that your trading account is only yours, and do not write me about being your account manager. This is forbidden! I do not have Whatsapp and Instagram for business purposes.
WARNING: Trading CFDs carries a high level of risk as the use of leverage can affect your financial position both positively and negatively. Trading on CFDs is not suitable for all investors, as it can result in a complete loss of the invested capital. Never invest more than you can afford. Be sure to familiarize yourself with all the risks before you start trading complex financial products.
pocketoption pocketoptionstrategy binaryoptionstrading
นอกจากการดูบทความนี้แล้ว คุณยังสามารถดูข้อมูลที่เป็นประโยชน์อื่นๆ อีกมากมายที่เราให้ไว้ที่นี่: ดูบทความเพิ่มเติมในหมวดหมู่LEARN FOREIGN LANGUAGE
ขอบคุณมากสำหรับการดูหัวข้อโพสต์ การใช้ use