Nodejs教程29:Node.js專案之四:新增路由,完成專案
查詢item_table表中的商品資料後,返回給前臺,並將回撥函式作為模組匯出。
示例程式碼:/lesson29/router/list.js
const connection = require('../lib/database') module.exports = async (res, query, post, files) => { try { // 查詢商品列表 const data = await connection.query(`SELECT * FROM item_table`) res.writeJson({ error: 0, // error為0則表示介面正常 data// 查詢到的商品列表資料 }) } catch (error) { console.error(error) res.writeJson({ error: 1, // error為1則表示接口出錯 msg: '資料庫出錯' // 介面的錯誤資訊 }) } res.end() } 複製程式碼
新增商品路由回撥函式
應禁止query語句使用如下寫法,容易造成注入攻擊。
connection.query(INSERT INTO item_table (title, price, count) VALUES('${title}, ${price} ${count}')
)
此時若使用者傳入引數如下:
http://localhost:8080/add?title=a ')%3B%20DELETE%20FROM%20item_table%3B%20SELECT%20(1&price=19.8&count=200
就會讓伺服器執行一個這樣的語句:
INSERT INTO item_table (title, price, count) VALUES('a'); DELETE FROM item_table; SELECT ('1', 19.8, 200) 複製程式碼
其意義為:
- 插入一個虛假資料
- 刪除item_table表中所有資料
- 返回一個虛假資料
這樣就會導致item_table表中的所有資料被刪除。
為防止注入攻擊,可以使用佔位符?代替需要插入資料庫的引數,第二個陣列引數中的3個值會按順序填充佔位符,該方法可以避免大部分注入攻擊,如下:
await connection.query(`INSERT INTO item_table (title, price, count) VALUES(?,?,?)`, [title, price, count]) 複製程式碼
示例程式碼:/lesson29/router/add.js
const connection = require('../lib/database') module.exports = async (res, query, post, files) => { let { title, price, count } = post // 判斷是否有傳參 if (!title || !price || !count) { res.writeJson({ error: 1, msg: '引數不合法' }) } else { // 將價格和數量轉為數字 price = Number(price) count = Number(count) // 判斷價格和數量是否非數字 if (isNaN(price) || isNaN(count)) { res.writeJson({ error: 1, msg: '引數不合法' }) } else { try { // 使用佔位符?代替需要插入資料庫的引數,第二個陣列引數中的3個值會按順序填充佔位符,該方法可以避免大部分注入攻擊。 await connection.query(`INSERT INTO item_table (title, price, count) VALUES(?,?,?)`, [title, price, count]) res.writeJson({ error: 0, msg: '新增商品成功' }) } catch (error) { console.error(error) res.writeJson({ error: 1, msg: '資料庫內部錯誤' }) } } } res.end() } 複製程式碼
刪除商品路由回撥函式
示例程式碼:/lesson29/router/del.js
const connection = require('../lib/database') module.exports = async (res, query, post, files) => { const ID = query.id if (!ID) { res.writeJson({ error: 1, msg: '引數不合法' }) } else { await connection.query(`DELETE FROM item_table WHERE ID=${ID}`) res.writeJson({ error: 0, msg: '刪除成功' }) } res.end() } 複製程式碼
新增各介面路由配置
在/router/index.js
中,引用各個介面的配置,並用addRouter方法新增到路由表中,即可在接收到請求時,查詢路由並進行處理。
示例程式碼:/lesson29/router/index.js
const { addRouter } = require('../lib/router') // 新增獲取商品列表介面 addRouter('get', '/list', require('./list')) // 新增商品介面 addRouter('post', '/add', require('./add')) // 刪除商品介面 addRouter('get', '/del', require('./del')) 複製程式碼
在主模組中引用路由
在/server.js中,引用router模組,就可以完成整個服務端的配置。
示例程式碼:/lesson29/server.js
const connection = require('./lib/database') const http = require('./lib/http') const router = require('./router') 複製程式碼
完成前端功能
在/static/index.html
中,使用jquery為前端頁面實現如下功能:
- 顯示商品列表
- 新增隨機名稱、價格、庫存的商品
- 刪除對應商品
示例程式碼:/lesson29/server.js
// 查詢商品列表的方法 function getList() { $.ajax({ url: '/list', dataType: 'json' }).then(res => { let html = `` res.data.forEach((item, index) => { html += ( ` <tr> <td>${item.title}</td> <td>¥${item.price}</td> <td>${item.count}</td> <td> <a data-id="${item.ID}" href="#" class="glyphicon glyphicon-trash">刪除</a> </td> </tr> ` ) }) $('tbody').html(html) }); } getList() // 點選新增按鈕,隨機新增一個商品 $('#addBtn').on('click', function () { $.ajax({ url: '/add', method: 'post', data: { title: `test${Math.floor(Math.random() * 100)}`, price: Math.floor(Math.random() * 100), count: Math.floor(Math.random() * 100) } }) .then((response) => { getList() }) }) // 點選刪除按鈕 $('tbody').on('click', 'a', function () { $.ajax({ url: '/del', data: { id: $(this).attr('data-id') } }) .then((response) => { getList() }) }) 複製程式碼
至此,原生Node.js的專案就全部完成了,這個專案“麻雀雖小五臟俱全”,可以很好地鍛鍊我們對Node.js的理解和開發能力。 當然從開發的過程也可以看到,使用原生Node.js開發效率較低,實際工作中還是會更多地使用Express、Koa等框架,進一步提高開發效率。