昨天已經可以靠打不同 API 方法的方式,來執行不同的 SQL 語法。
但有沒有覺得哪裡怪怪的,
為什麼我只能新增名為 testBook-1
的書名?
或是為什麼我只能更新 id = 1
的書名?
在 Day 11 那天有提到一些基礎 SQL 語法可以對資料庫進行 CRUD ,
現在我們來修改一下原本的程式,讓使用上可以更有彈性。
用一個 app.use(express.json())
在調整路由程式之前,我們需要先到 app.js
檔案,多調用一個 app.use(express.json())
的 Middleware,讓外部傳來的 JSON 請求,轉換為物件給後端進行後面邏輯的處理。
// app.js
app.use(express.json())
調整 book.js 路由相關程式
將我們想要動態調整的欄位,改為從外部傳進來,並且將 SQL 語法加入傳進來的變數。
// routes/modules/book.js
router.post('/', async (req, res) => {
const bookName = req.body.bookName // 設定一個要新增的書名
try {
// 建立與數據庫的連接
const connection = await mysqlConnection()
// 將新增的書名改為變數
await connection.query(`INSERT INTO booktest (bookName) VALUES ('${bookName}')`)
// 關閉連接
connection.end()
} catch (error) {
console.error('連接數據庫時出現錯誤:', error)
}
// res.send('Post a book')
res.render('page',{'text': `add a new book: ${bookName}`})
})
router.delete('/:id', async (req, res) => { // 設定一個要刪除書名的 id
const id = req.params.id
try {
// 建立與數據庫的連接
const connection = await mysqlConnection()
// 將想要刪除的 id 改為變數
await connection.query(`DELETE FROM booktest WHERE id = ${id}`)
// 關閉連接
connection.end()
} catch (error) {
console.error('連接數據庫時出現錯誤:', error)
}
// res.send('Delete the book')
res.render('page',{'text': `Delete the book number ${id}`})
})
如此一來,資料庫可以依照我們所想要使用的資料進行操作,
也可以隨我們需求進行新增與刪除資料。
試著用 Postman 打看看新增的路由。
看資料庫也成功新增了書名為 bookName1 的資料。
看起來一切都能運行的很順利,但這其實有一個很嚴重的問題 !
那些變數可以隨我們心情傳進來進行修改其實是很危險的。
如果遇到像駭客等有心人士,
這樣的寫法很容易發生 SQL 注入( SQL injection ) 的網路攻擊!
也就是駭客可以利用這些要傳給資料庫進行資料異動的變數,寫入惡意的 SQL,
造成你原有的資料被竊取或遺失。
例如,我們在 delete 方法的 id 輸入 2 or 1 = 1
哇我們本來只要刪掉 id = 2 的書結果 全部刪掉了!
這樣也太危險了吧!不小心你的資料就會被別人刪光或偷走。
所以記得!在程式下 SQL 時要使用以下方法!
我們需要使用 占位符 ?
,確保是使用正確的參數查詢,
而不是直接將用戶輸入插入 SQL 語句。
我們用以下範例來說明:
connection.query(`DELETE FROM booktest WHERE id = ?`, id)
以上範例可以看到,
只要將原本需要傳遞變數的部分改為 ?
,並將要帶入的變數加在逗點後面,
程式就會將後面的變數依序帶入到 ?
的位置來執行。
但如果我們要好幾個變數,不是就要用好幾個?
,
又要依序寫入程式很容易造成錯誤或混亂。
為了使用上和維護上的方便,
一般公司都會傾向不要在程式直接寫 SQL,而使用 ORM 來對資料庫做 CRUD。
這部分我們就留到明天再說啦,大家掰掰~