node简单功能搭建

前言

最近看了美团技术团队发布的文章,flutter的应用已经越来越娴熟。毕竟前端技术迭代那么快,闭门造车注定会被淘汰,迫不得已只能开始学习dart。刚好看到http请求和websocket,没有后端服务,直接卡住。这种情况也不是第一次遇到了,以前就是简单写个能运行的,就过去了,这次下次决心,直接把常用的服务端需要的内容整理了一份。

开始

首先,先确定需要哪些功能,简单罗列了一下

1.基本的增删改查(包括分页)

2.token的获取和验证(登录)

3.文件上传

4.websocket

第一步,先启动个项目,安装下express的脚手架,新建一个express工程

cnpm install -g express

cnpm install -g express-generator

express myApp
复制代码

然后,开始准备下需要的npm包,标注出来的是额外下载的,其他都是脚手架自带的。

"dependencies": {
  "cookie-parser": "~1.4.4", 
  "cors": "^2.8.5", // 解决跨域问题
  "cross-env": "^7.0.3", // 控制运行时的环境变量
  "debug": "~2.6.9",
  "express": "~4.16.1",
  "http-errors": "~1.6.3",
  "jade": "~1.11.0",
  "jsonwebtoken": "^8.5.1", // token的生成与解密
  "morgan": "~1.9.1",
  "multiparty": "^4.2.2", // 用来解决上传文件的form表单解析
  "nodejs-websocket": "^1.7.2", // 用于启动websocket
  "nodemon": "^2.0.7" // 方便调试
}
复制代码

一切准备好以后,就可以开始码代码了。

一. 先完成简单的增删改查的接口。

const createGoodsList = function (number = 8) {
  const arr = [];
  for (let i = 1; i <= number; i++) {
    arr.push({
      id: i,
      name: 'goods-' + i,
      price: i
    })
  }
  return arr;
};
module.exports = createGoodsList;
复制代码
const express = require('express');
const createGoods = require('../data/create-goods');
const router = express.Router();
let goodsPageList = createGoods(999);
/* goods router */
router
  .get('/', function(req, res, next) {
     const { pageNum = 1, pageSize = 10 } = req.query;
     const count = goodsPageList.length; // 数据总量
     const allPage = Math.ceil(count / pageSize); // 总共几页
     const hasNextPage = allPage > pageNum; // 是否有下一页
     const start = (pageNum - 1) * pageSize;
     const end = pageNum * pageSize;
     const list = goodsPageList.slice(start, end);
     res.json({
       code: 0,
       data: {
         list,
         hasNextPage,
         pages: allPage,
         count
       },
       msg: '操作成功'
     })
  })
  .post('/', function (req, res) {
    const g = req.body;
    goodsPageList.unshift(g);
    res.json({
      code: 0,
      data: null,
      msg: '操作成功'
    });
  })
  .put('/:id', function (req, res) {
    const g = req.body;
    const id = +req.params.id;
    console.log('id', id);
    goodsPageList = goodsPageList.map(v => {
      if (v.id === id) {
        return g;
      }
      return v;
    });
    res.json({
      code: 0,
      data: null,
      msg: '操作成功'
    });
  })
  .delete('/:id', function(req, res) {
    const id = +req.params.id;
    console.log('id', id);
    goodsPageList = goodsPageList.filter(v => v.id !== id);
    res.json({
      code: 0,
      data: null,
      msg: '操作成功'
    });
  });
module.exports = router;
复制代码

因为为了简单,没有使用数据库服务,商品的创建模拟了一个数据列,用于简单的分页查询和其他操作。然后把路由添加到app中,就完成了第一步。

二. token的生成与验证。

先封装一下需要使用的方法

const jwt = require('jsonwebtoken');
const TOKEN_SECRET = "MY_SECRET";
const myToken = {
  // 根据数据和secret 生成token
  encrypt(data, time) {
    return jwt.sign(data, TOKEN_SECRET, {
      expiresIn: time || '24h'
    });
  },
  // 获取token信息
  decrypt(token) {
    try {
      const data = jwt.verify(token, TOKEN_SECRET);
      return {
        token: true,
        data
      }
    } catch (e) {
      return {
        token: false,
        data: e
      }
    }
  },
  // 校验token
  checkToken(req, res, next) {
    const token = req.headers.authorization;
    const data = myToken.decrypt(token);
    console.log('token', data);
    if (data.token) {
      const id = data.id;
      next();
      return;
    }
    res.json({
      code: 401,
      data: null,
      msg: '用户信息已失效,请重新登录'
    })
  }
};
module.exports = myToken;
复制代码

模拟登陆接口生成token,

var express = require('express');
var router = express.Router();
var Token = require('../utils/token');
/* GET home page. */
router.post('/login', function(req, res, next) {
  const data = {
    name: 'yyh',
    age: 27
  };
  const t = Token.encrypt(data);
  res.json({
    code: 0,
    data: t,
    msg: '操作成功'
  })
});
module.exports = router;
复制代码

然后,在api调用时,添加token的验证

app.use('/', indexRouter); // 登录
app.use('/api', Token.checkToken); // /api/* 需要验证token
app.use('/api/goods', goodsRouter) // 增删改查接口
app.use('/api/upload', uploadRouter) // 上传接口
复制代码

三. 创建websocket服务

这个比较简单,引下依赖就能使用了,但是比较简单,如果后续功能需要,还是要继续完善

const ws = require('nodejs-websocket');
const createServer = () => {
  return ws.createServer(connection => {
    connection.timeStamp = Date.now();
    // console.log('create conn', connection);
    console.log('有新的连接');
    connection.on('text', (result) => {
      const data = JSON.parse(result)
      console.log('收到消息111', data);
    })
    connection.on('connect', (code) => {
      console.log('开启连接', code)
    })
    connection.on('close', (code) => {
      console.log('关闭连接', code)
      clearInterval(timer)
    })
    connection.on('error', (code) => {
      console.log('异常关闭', code)
      clearInterval(timer)
    })
    
    // 定时发消息
    const timer = setInterval(() => {
      connection.send('1111')
    }, 3000)
  })
}

const server = createServer();
module.exports = {
  websocket: server
};
复制代码
// 在app中引入,并启动websocket
websocket.listen(9999, function () {
  console.log('server start')
});
复制代码

四. 文件上传

首先,引入 multiparty 包,用来初始化传过来的数据文件,配置路径

const multiparty = require('multiparty')

const createUpload = function (dir) {
  /* 生成multiparty对象,并配置上传目标路径 */
  const form = new multiparty.Form();
  // 设置编码
  form.encoding = 'utf-8';
  // 设置文件存储路径,以当前编辑的文件为相对路径
  form.uploadDir = dir;
  // 设置文件大小限制
  form.maxFilesSize = 100 * 1024 * 1024;
  return form;
};
module.exports = {
  createUpload
};
复制代码

然后,写个上传的接口,文件上传的功能也就完成了。

const express = require('express');
const router = express.Router();
const { createUpload } = require('../utils/upload-form');
const fs = require('fs');
router.post('/', function(req, res, next) {
  // 配置路径
  const form = createUpload('./public/upload');
  // 解析文件
  form.parse(req, function (err, fields, files) {
    console.log('files', files);
    const file = files.file[0];
    // 重命名文件名
    const name = Date.now() + '-' + file.originalFilename;
    const oldPath = file.path;
    const newPath = form.uploadDir + "/" + name;
    fs.renameSync(oldPath, newPath);
    res.json({
      code: 0,
      data: newPath,
      msg: '操作成功'
    })
  });
});
module.exports = router;
复制代码

结语

只是简单整理了一下,代码的编写过程一切从简,也没有进行过多的设计,主要为了一劳永逸,把简要功能写完,就去继续我的dart学习了。希望下次写的文章已经是跟flutter相关的啦,哈哈~

git地址:git@github.com:lyingdog/node-server…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享