Middleware


Posted by ericcch24 on 2020-10-16

  • Express 在處理 request 到收到 response 的這段過程,中間會經過一系列的 middleware 處理。

例如:

app.get('/todos', todoController.getAll)

app.get('/todos/:id', todoController.get)

上面的todoController.getAlltodoController.get 就算是 middleware

其中app.use((req, res, next) => {}) 可以讓整個應用程式都可以使用這個 middleware,==加第三個參數 next 才會把控制權交給下一個 middleware==

app.use((req, res, next) => {
  console.log('time:', new Date())
  next() 
  // 加 next 才會把控制權交給下一個 middleware
  // 不然就只會跑到上面的印出日期就停了
})

解析 Request 必備:body-parser

  • 在 express 內建原本只能拿 get 方法的網址列上的 query string 資料,post 的話就要用 body-parser 才能拿到 requset body 內部的資料。

  • index.js
    ```javascript=
    const bodyParser = require('body-parser')
    .
    .
    app.use(bodyParser.urlencoded({ extended: false }))
    app.use(bodyParser.json())
    // 以上的 middleware 可以幫助解析 request body
    .
    .
    app.post('/todos', todoController.newTodo)
    // 在列出所有 todo 的頁面 post 新增的 todo

app.get('/', todoController.addTodo)
// 在根目錄 input 內容
.
.

* controller
```javascript=
  newTodo: (req, res) => {
    const content = req.body.content 
    // 可以拿到 addTodo 那邊 input 的內容
    // 如果沒有設定 index 那邊的 body-parser 就拿不到
    todoModel.add(content, (err) => {
      if(err) return console.log(err)
      res.redirect('/todos') // 成功後導回'/todos'
    })
  },

  addTodo: (req, res) => {
    res.render('addTodo')
  },
  • model
    add: (content, cb) => {
      db.query('insert into todos(content) values(?) ', [content], 
      (err, results) => {
        if (err) return cb(err);
        cb(null);
      });
    }
    
  • view -> addTodo
    ```htmlembedded=

    Add Todo

Content:

---

## 負責管理 Session 的 Session middleware: express-session

* index.js
```javascript=
.
.
const session = require('express-session')
.
.
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))
// 管理 session 的 middleware
.
.
.
app.get('/', todoController.addTodo)
app.get('/login', (req, res) => {
  res.render('login')
})
app.post('/login', (req, res) => {
  if(req.body.password === '123') {
    req.session.isLogin = true
    res.redirect('/')
  } else {
    res.redirect('/login')
  }
})
app.get('/logout', (req, res) => {
  req.session.isLogin = false
  res.redirect('/')
})
  • controller
    addTodo: (req, res) => {
    res.render('addTodo', {
      isLogin: req.session.isLogin 
      // 傳入 isLogin 參數
      // 讓 addTodo 根據 isLogin 的狀態來決定要印出什麼內容
    })
    },
    
  • view: login
    ```htmlembedded=

    Login

Password:

* view: addTodo
```htmlembedded=
<h1>Add Todo</h1>

<% if (isLogin) { %>
  你已經登入 <a href="/logout">logout</a>
<% } else { %>
  你還沒登入
<% } %>


<form method="POST" action="/todos" >
  Content: <input type="text" name="content" />
  <input type="submit" />
</form>

顯示錯誤訊息神器:connect-flash

錯誤訊息 flash,重整一次頁面會消失,只會顯示發生錯誤的那一次

  • index.js
    .
    .
    const flash = require('connect-flash');
    .
    .
    app.use(flash())
    // 錯誤訊息 flash,重整一次頁面會消失,只會顯示發生錯誤的那一次
    .
    .
    app.get('/login', (req, res) => {
    res.render('login', {
      errorMessage: req.flash('errorMessage')
      // 在登入頁面拿取存在 flash 內的參數
    })
    })
    app.post('/login', (req, res) => {
    if(req.body.password === '123') {
      req.session.isLogin = true
      res.redirect('/')
    } else {
      req.flash('errorMessage', 'password incorrect') 
      // 登入失敗時設置兩參數 (key, value)
      res.redirect('/login')
    }
    })
    
  • view: login
    ```htmlmixed=

    Login

<%= errorMessage %>

Password:


---
## 設定可以在 view 隨意存取的參數
* 因為在一堆地方都要傳入提到的 `isLogin`, `errorMessage` 等參數,很麻煩。
* 此時將要用的東西放入`res.locals`(類似全域變數的概念),在 view 那邊就可以直接使用。
* 在 `res.locals` 指定好的參數,view 就可以直接使用
```javascript=
app.use((req, res, next) => {
  res.locals.isLogin = req.session.isLogin
  res.locals.errorMessage = req.flash('errorMessage')
  // 將要設定的東西放入 res.locals,view 就可以直接使用
  next();
})
  • 設定好之後 render 的部分就不用再傳參數給 view,在 view 就可以直接使用。
app.get('/login', (req, res) => {
  res.render('login', {
    errorMessage: req.flash('errorMessage')
    // 在登入頁面拿取存在 flash 內的參數
  })
})

===

app.get('/login', (req, res) => {
  res.render('login')
});

addTodo: (req, res) => {
  res.render('addTodo', {
    isLogin: req.session.isLogin 
    // 傳入 isLogin 參數
    // 讓 addTodo 根據 isLogin 的狀態來決定要印出什麼內容
  })
}

===

addTodo: (req, res) => {
  res.render('addTodo')
}
tags: Week17

#week17







Related Posts

Linux小技巧暨問題集

Linux小技巧暨問題集

Template Literals 與 Destructuring

Template Literals 與 Destructuring

IC Design Contest Cell-Based 考古題 分享 及 比賽心得

IC Design Contest Cell-Based 考古題 分享 及 比賽心得


Comments