前言
最近看了美团技术团队发布的文章,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相关的啦,哈哈~
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END