阅读 560

Nodejs教程29:Node.js项目之四:添加路由,完成项目

阅读更多系列文章请访问我的GitHub博客,示例代码请访问这里

添加各接口路由配置

获取商品列表路由回调函数

查询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)
复制代码

其意义为:

  1. 插入一个虚假数据
  2. 删除item_table表中所有数据
  3. 返回一个虚假数据

这样就会导致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为前端页面实现如下功能:

  1. 显示商品列表
  2. 添加随机名称、价格、库存的商品
  3. 删除对应商品

示例代码:/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等框架,进一步提高开发效率。

关注下面的标签,发现更多相似文章
评论