npm install koa -S
const Koa = require('koa');let { Port } = require('./config');let app = new Koa();// responseapp.use(ctx => { ctx.body = 'Hello Koa';});// 监听服务器启动端口app.listen(Port, () => { console.log(`服务器启动在${ Port }端口`);});
就这样一个node.js服务器就启动起来了,
使用postman测试一下
思路:
└── src # 源代码目录 └── routers # 路由目录 └── router # 子路由目录 ├── usersRouter.js # 用户模块子路由 ├── ... # 更多的模块子路由 ├── index.js # 路由入口文件
npm install koa-router -S
const Router = require('koa-router');// 导入控制层const usersController = require('../../controllers/usersController');let usersRouter = new Router();usersRouter .post('/users/login', usersController.Login)module.exports = usersRouter;
const Router = require('koa-router');let Routers = new Router();const usersRouter = require('./router/usersRouter');Routers.use(usersRouter.routes());module.exports = Routers;
// 使用路由中间件const Routers = require('./routers');app.use(Routers.routes()).use(Routers.allowedMethods());
使用postman测试接口localhost:5000/users/login
思路:
db.query('select * from users where userName = ? and password = ?', ['userName', 'password'])
npm install mysql -S
在config.js添加如下代码,然后在db.js引入
// 数据库连接设置dbConfig: { connectionLimit: 10, host: 'localhost', user: 'root', password: '', database: 'storeDB'}
创建"./src/models/db.js"
var mysql = require('mysql');const { dbConfig } = require('../config.js');var pool = mysql.createPool(dbConfig);var db = {};db.query = function (sql, params) { return new Promise((resolve, reject) => { // 取出连接 pool.getConnection(function (err, connection) { if (err) { reject(err); return; } connection.query(sql, params, function (error, results, fields) { console.log(`${ sql }=>${ params }`); // 释放连接 connection.release(); if (error) { reject(error); return; } resolve(results); }); }); });}// 导出对象module.exports = db;
更多的信息请参考mysql文档。
思路:
let { userName, password } = ctx.request.body;
npm install koa-body -S
在config.js配置上传文件路径
uploadDir: path.join(__dirname, path.resolve('../public/')), // 上传文件路径
在app.js使用koa-body中间件
const KoaBody = require('koa-body');let { uploadDir } = require('./config');
// 处理请求体数据app.use(KoaBody({ multipart: true, // parsedMethods默认是['POST', 'PUT', 'PATCH'] parsedMethods: ['POST', 'PUT', 'PATCH', 'GET', 'HEAD', 'DELETE'], formidable: { uploadDir: uploadDir, // 设置文件上传目录 keepExtensions: true, // 保持文件的后缀 maxFieldsSize: 2 * 1024 * 1024, // 文件上传大小限制 onFileBegin: (name, file) => { // 文件上传前的设置 // console.log(`name: ${name}`); // console.log(file); } }}));
思路:
在app.js添加如下代码
// 异常处理中间件app.use(async (ctx, next) => { try { await next(); } catch (error) { console.log(error); ctx.body = { code: '500', msg: '服务器未知错误' } }});
思路:
npm install koa-static -S
在config.js配置静态资源路径
staticDir: path.resolve('../public'), // 静态资源路径
在app.js使用koa-static中间件
const KoaStatic = require('koa-static');let { staticDir } = require('./config');
// 为静态资源请求重写urlapp.use(async (ctx, next) => { if (ctx.url.startsWith('/public')) { ctx.url = ctx.url.replace('/public', ''); } await next();});// 使用koa-static处理静态资源app.use(KoaStatic(staticDir));
使用浏览器测试接口http://localhost:5000/public/imgs/a.png
思路:
npm install koa-session -S
创建"./src/middleware/session.js"
let store = { storage: {}, set (key, session) { this.storage[key] = session; }, get (key) { return this.storage[key]; }, destroy (key) { delete this.storage[key]; }}let CONFIG = { key: 'koa:session', maxAge: 86400000, autoCommit: true, // 自动提交标头(默认为true) overwrite: true, // 是否可以覆盖(默认为true httpOnly: true, // httpOnly与否(默认为true) signed: true, // 是否签名(默认为true) rolling: false, // 强制在每个响应上设置会话标识符COOKIE。到期重置为原始的maxAge,重置到期倒数 renew: false, // 在会话即将到期时更新会话,因此我们始终可以使用户保持登录状态。(默认为false) sameSite: null, // 会话COOKIE sameSite选项 store // session池}module.exports = CONFIG;
在app.js使用koa-session中间件
const Session = require('koa-session');// sessionconst CONFIG = require('./middleware/session');app.keys = ['session app keys'];app.use(Session(CONFIG, app));
思路:
在"./src/middleware/isLogin.js",创建一个验证是否登录的函数
module.exports = async (ctx, next) => { if (ctx.url.startsWith('/user/')) { if (!ctx.session.user) { ctx.body = { code: '401', msg: '用户没有登录,请登录后再操作' } return; } } await next();};
在app.js使用登录拦截器
// 判断是否登录const isLogin = require('./middleware/isLogin');app.use(isLogin);
思路:
└── src # 源代码目录 └── routers # 路由目录 └── router # 子路由目录 ├── usersRouter.js # 用户模块子路由 ├── ... # 更多的模块子路由 ├── index.js # 路由入口文件 └── controllers # 控制层目录 ├── usersController.js # 用户模块控制层 ├── ... # 更多的模块控制层 └── models # 数据持久层目录 └── dao # 模块数据持久层目录 ├── usersDao.js # 用户模块数据持久层 ├── ... # 更多的模块数据持久层 ├── db.js # 数据库连接函数 ├── app.js # 入口文件
接口文档
create database storeDB;use storeDB;create table users( user_id int primary key auto_increment, userName char (20) not null unique, password char (20) not null, userPhoneNumber char(11) null);
const Router = require('koa-router');// 导入控制层const usersController = require('../../controllers/usersController');let usersRouter = new Router();usersRouter .post('/users/login', usersController.Login) .post('/users/findUserName', usersController.FindUserName) .post('/users/register', usersController.Register)module.exports = usersRouter;
const userDao = require('../models/dao/usersDao');const { checkUserInfo, checkUserName } = require('../middleware/checkUserInfo');module.exports = { /** * 用户登录 * @param {Object} ctx */ Login: async ctx => { let { userName, password } = ctx.request.body; // 校验用户信息是否符合规则 if (!checkUserInfo(ctx, userName, password)) { return; } // 连接数据库根据用户名和密码查询用户信息 let user = await userDao.Login(userName, password); // 结果集长度为0则代表没有该用户 if (user.length === 0) { ctx.body = { code: '004', msg: '用户名或密码错误' } return; } // 数据库设置用户名唯一 // 结果集长度为1则代表存在该用户 if (user.length === 1) { const loginUser = { user_id: user[0].user_id, userName: user[0].userName }; // 保存用户信息到session ctx.session.user = loginUser; ctx.body = { code: '001', user: loginUser, msg: '登录成功' } return; } //数据库设置用户名唯一 //若存在user.length != 1 || user.length!=0 //返回未知错误 //正常不会出现 ctx.body = { code: '500', msg: '未知错误' } }, /** * 查询是否存在某个用户名,用于注册时前端校验 * @param {Object} ctx */ FindUserName: async ctx => { let { userName } = ctx.request.body; // 校验用户名是否符合规则 if (!checkUserName(ctx, userName)) { return; } // 连接数据库根据用户名查询用户信息 let user = await userDao.FindUserName(userName); // 结果集长度为0则代表不存在该用户,可以注册 if (user.length === 0) { ctx.body = { code: '001', msg: '用户名不存在,可以注册' } return; } //数据库设置用户名唯一 //结果集长度为1则代表存在该用户,不可以注册 if (user.length === 1) { ctx.body = { code: '004', msg: '用户名已经存在,不能注册' } return; } //数据库设置用户名唯一, //若存在user.length != 1 || user.length!=0 //返回未知错误 //正常不会出现 ctx.body = { code: '500', msg: '未知错误' } }, Register: async ctx => { let { userName, password } = ctx.request.body; // 校验用户信息是否符合规则 if (!checkUserInfo(ctx, userName, password)) { return; } // 连接数据库根据用户名查询用户信息 // 先判断该用户是否存在 let user = await userDao.FindUserName(userName); if (user.length !== 0) { ctx.body = { code: '004', msg: '用户名已经存在,不能注册' } return; } try { // 连接数据库插入用户信息 let registerResult = await userDao.Register(userName, password); // 操作所影响的记录行数为1,则代表注册成功 if (registerResult.affectedRows === 1) { ctx.body = { code: '001', msg: '注册成功' } return; } // 否则失败 ctx.body = { code: '500', msg: '未知错误,注册失败' } } catch (error) { reject(error); } }};
const db = require('../db.js');module.exports = { // 连接数据库根据用户名和密码查询用户信息 Login: async (userName, password) => { const sql = 'select * from users where userName = ? and password = ?'; return await db.query(sql, [userName, password]); }, // 连接数据库根据用户名查询用户信息 FindUserName: async (userName) => { const sql = 'select * from users where userName = ?'; return await db.query(sql, [userName]); }, // 连接数据库插入用户信息 Register: async (userName, password) => { const sql = 'insert into users values(null,?,?,null)'; return await db.query(sql, [userName, password]); }}
module.exports = { /** * 校验用户信息是否符合规则 * @param {Object} ctx * @param {string} userName * @param {string} password * @return: */ checkUserInfo: (ctx, userName = '', password = '') => { // userName = userName ? userName : ''; // password = password ? password : ''; // 判断是否为空 if (userName.length === 0 || password.length === 0) { ctx.body = { code: '002', msg: '用户名或密码不能为空' } return false; } // 用户名校验规则 const userNameRule = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/; if (!userNameRule.test(userName)) { ctx.body = { code: '003', msg: '用户名不合法(以字母开头,允许5-16字节,允许字母数字下划线)' } return false; } // 密码校验规则 const passwordRule = /^[a-zA-Z]w{5,17}$/; if (!passwordRule.test(password)) { ctx.body = { code: '003', msg: '密码不合法(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)' } return false; } return true; }, /** * 校验用户名是否符合规则 * @param {type} * @return: */ checkUserName: (ctx, userName = '') => { // 判断是否为空 if (userName.length === 0) { ctx.body = { code: '002', msg: '用户名不能为空' } return false; } // 用户名校验规则 const userNameRule = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/; if (!userNameRule.test(userName)) { ctx.body = { code: '003', msg: '用户名不合法(以字母开头,允许5-16字节,允许字母数字下划线)' } return false; } return true; }}
登录测试
注册测试
查找用户名测试
作者:hai_27
链接:https://juejin.im/post/5e6de50f6fb9a07cae137bf5