Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例

news/2024/5/20 10:48:08/文章来源:https://blog.csdn.net/dbow21397/article/details/101985232

目录

前言

  前面一有写到一篇Node.js+Express构建网站简单示例:http://www.cnblogs.com/zhongweiv/p/nodejs_express_webapp.html

  这篇还是用以前的例子, 用Node.js+Koa2构建

 

  Koa:   https://github.com/koajs/koa

       http://koa.bootcss.com  (中文)

 

  Koa就不多介绍了,前面也写过Express,同一个团队打造,前面也过express文章,对比着看,自然可以看出些优点!

 

搭建项目及其它准备工作

创建数据库

CREATE DATABASE IF NOT EXISTS nodesample CHARACTER SET UTF8;USE nodesample;SET FOREIGN_KEY_CHECKS=0;DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`UserName` varchar(64) NOT NULL COMMENT '用户名',`UserPass` varchar(64) NOT NULL COMMENT '用户密码',PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户信息表';

创建Koa2项目

  安装koa-generator:  https://github.com/17koa/koa-generator

npm install -g koa-generator

 安装成功后下图(版本:1.1.16)

 

 然后创建Koa2项目,安装相关依赖项

cd 工作目录
koa2 项目名
cd 项目目录 && npm install

安装项目其它需要包

1.安装使用MySQL需要的包

npm install --save mysql

 没有使用过的可以看我以前写的相关操作文章:http://www.cnblogs.com/zhongweiv/p/nodejs_mysql.html

 2.安装ejs(koa2默认为jade,我习惯使用ejs)

npm install --save ejs

没有使用过的可以看我以前写的相关操作文章:http://www.cnblogs.com/zhongweiv/p/nodejs_express.html

3.安装Session存储相关包(存储到redis)

npm install koa-session  https://github.com/koajs/session

npm install --save koa-session

koa-session-redis https://github.com/Chilledheart/koa-session-redis

npm install --save koa-session-redis

清除冗余文件并重新规划项目目录

 1.删除掉创建项目后自带的views和routes下的文件

 2.重新规划项目目录,规划后如下

目录规则解释:

1.新增pub目录:主要为了统一存放"数据访问"、"业务逻辑"、"公共方法文件"、"数据库帮助文件"、"配置文件"等

2.新增pub目录下utils目录:主要为了统一存放类似"公共函数文件"、"返回值文件"、"枚举文件"等公共文件

3.新增pub目录下config目录:主要为了统一存放各种类型的配置文件

4.新增pub目录下db目录:主要为了统一存放各种数据库帮助类,比如:"mysql-helper.js"、"mongo-helper.js"等等

5.新增pub目录下model目录:主要为了统一存放各种数据库各表CURD操作

6.新增pub目录下bll目录:主要为了统一存放各种业务逻辑的具体实现

配置文件

 从上面的图可以看出,我在pub下新建的config目录下新建了一个config.js

 这个config.js中将编写“开发环境”和“发布环境”中所需的配置,代码如下

/*** 配置文件*/
//发布配置
const production = {//服务器端口SERVER_PORT : 3000,//REDIS配置
    REDIS: {host: 'localhost',            port: 6379,password: "abcd",maxAge: 3600000},//MYSQL数据库配置
    MYSQL: {host: "localhost",user: "root",password: "abcd",port: "3306",database: "nodesample",supportBigNumbers: true,multipleStatements: true,timezone: 'utc'}}//开发配置
const development = {//服务器端口SERVER_PORT : 3000,//REDIS配置
    REDIS: {host: 'localhost',            port: 6379,password: "abcd",maxAge: 3600000},//MYSQL数据库配置
    MYSQL: {host: "localhost",user: "root",password: "abcd",port: "3306",database: "nodesample",supportBigNumbers: true,multipleStatements: true,timezone: 'utc'}}const config = developmentmodule.exports = config

规划示例路由,并新建相关文件

 示例中将有注册、登录功能,先规划好路由,新建routes、views下的相关需要的文件(如项目目录图中文件),并修改app.js文件

const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')

const config = require('./pub/config/config.js');
const session = require('koa-session');
const RedisStore = require('koa2-session-redis');const index = require('./routes/index')
const reg = require('./routes/reg')
const login = require('./routes/login')
const logout = require('./routes/logout')// error handler
onerror(app)// middlewares
app.use(bodyparser({enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))app.use(views(__dirname + '/views', {extension: 'ejs'
}))// logger
app.use(async (ctx, next) => {const start = new Date()await next()const ms = new Date() - startconsole.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})app.keys = ['Porschev'];
const redis_conf = {  key: 'Porschev',maxAge: config.REDIS.maxAge,overwrite: true,httpOnly: true,  rolling: false,sign: true,store: new RedisStore({host: config.REDIS.host,port: config.REDIS.port,    password: config.REDIS.password    })
};app.use(session(redis_conf, app));// routes
app.use(index.routes(), index.allowedMethods())
app.use(reg.routes(), reg.allowedMethods())
app.use(login.routes(), login.allowedMethods())
app.use(logout.routes(), logout.allowedMethods())// error-handling
app.on('error', (err, ctx) => {console.error('server error', err, ctx)
});app.listen(config.SERVER_PORT, () => {console.log(`Starting at port ${config.SERVER_PORT}!`)
});module.exports = app

注意看红色标记修改或增加的部分

实现数据访问和业务逻辑相关方法

 1.首先编写一个mysql-helper.js方便以连接池的方式进行操作

const config = require('./../config/config.js')
const mysql = require("mysql")const pool = mysql.createPool(config.MYSQL)let query = function(sql, args) {return new Promise((resolve, reject) => {pool.getConnection(function(err, connection) {if (err) {resolve(err)} else {connection.query(sql, args, (err, result) => {if (err) {reject(err)} else {resolve(result)}connection.release()})}})})}module.exports = { query 
}

2.编写数据访问相关方法(model目录下的userinfo.js),如下

const mysqlHelper = require('./../db/mysql-helper.js')const userinfo = {/*** 增加一条数据* @param  {object} args  参数* @return {object}       结果*/async add ( args ) {let sql = 'INSERT INTO userinfo(UserName, UserPass) VALUES(?, ?)'let params = [args.username, args.userpass]let result = await mysqlHelper.query(sql, params)return result},/*** 根据UserName得到一条数据* @param  {object} args  参数* @return {object}       结果*/async getByUserName( args ){let sql = 'SELECT Id, UserName, UserPass FROM userinfo WHERE UserName = ?'let params = [args.username]let result = await mysqlHelper.query(sql, params)return result},/*** 根据UserName得到数量* @param  {object} args  参数* @return {object}       结果*/async getCountByUserName( args ){let sql = 'SELECT COUNT(1) AS UserNum FROM userinfo WHERE UserName = ?'let params = [args.username]let result = await mysqlHelper.query(sql, params)return result},}module.exports = userinfo

3.在写业务逻辑之前先规划好返回值(utils目录下retcode.js)

/** 返回码*/
const RetCode = {SessionExpired: -1,             //session过期Fail: 0,                        //失败Success: 1,                     //成功ArgsError: 2,                   //参数错误UserExisted: 10,                //用户已经存在UsernameOrPasswordError: 11,    //用户名或者密码错误      UserNotExist: 12,               //用户不存在    
};module.exports = RetCode
retcode.js

4.编写“登录”、“注册”等业务逻辑(bll下userinfo.js)

const usermodel = require('./../model/userinfo.js')
const retCode = require('./../utils/retcode.js')const userinfo = {/*** 注册* @param  {object} ctx   上下文* @return {object}       结果*/async register ( ctx ) {let form = ctx.request.bodyconst args = {username: form.username,userpass: form.userpass}let result = {code: retCode.Success,    data: null}//验证非空if(!args.username || !args.userpass){result.code = retCode.ArgsError        return result}//根据用户名得到用户数量let userNumResult = await usermodel.getCountByUserName(args)//用户名已被注册if(userNumResult[0].UserNum > 0){result.code = retCode.UserExisted        return result}//插入注册数据let userResult = await usermodel.add(args)if(userResult.insertId <= 0){result.code = retCode.Fail        return result}return result},/*** 登录* @param  {object} ctx   上下文* @return {object}       结果*/async login ( ctx ) {let form = ctx.request.bodyconst args = {username: form.username,userpass: form.userpass}let result = {code: retCode.Success,    data: null}//验证非空if(!args.username || !args.userpass){result.code = retCode.ArgsError        return result}//根据用户名得到用户信息let userResult = await usermodel.getByUserName(args)//用户不存在if(userResult.length == 0){result.code = retCode.UserNotExist        return result}//用户名或密码错误if(userResult[0].UserName != args.username || userResult[0].UserPass != args.userpass){result.code = retCode.UsernameOrPasswordError        return result}//将用户ID存入Session中ctx.session = {id: userResult[0].Id}return result},}module.exports = userinfo

注册

1.views目录下reg.ejs

<html>
<head>
<title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title>
</head>
<body>
<h1><%= title %></h1>
登录名:<input type="text" id="txtUserName" maxlength="20" />
<br/>
<br/>
密码:<input type="password" id="txtUserPwd" maxlength="12" />
<br/>
<br/>
密码:<input type="password" id="txtUserRePwd" maxlength="12" />
<br/>
<br/>
<input type="button" id="btnSub" value="注册" />
</body>
</html><script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script>
<script src="/javascripts/md5.js" type="text/javascript"></script><script type="text/javascript">   $(function(){$('#btnSub').on('click', function(){var $txtUserName = $('#txtUserName'),txtUserNameVal = $.trim($txtUserName.val()),$txtUserPwd = $('#txtUserPwd'),txtUserPwdVal = $.trim($txtUserPwd.val()),$txtUserRePwd = $('#txtUserRePwd'),txtUserRePwdVal = $.trim($txtUserRePwd.val());if(txtUserNameVal.length == 0){alert('用户名不能为空');                return false;}if(txtUserPwdVal.length == 0){                alert('密码不能为空');                return false;}if(txtUserRePwdVal.length == 0){alert('重复密码不能为空');   return false;}if(txtUserPwdVal != txtUserRePwdVal){                 alert('两次密码不一致');                 return false;}$.ajax({url: '/reg',type: 'POST',dataType: 'json',data: {username: txtUserNameVal,                    userpass: hex_md5(txtUserPwdVal)                                        },beforeSend: function (xhr) {},success: function (res) {if (res != null && res.code) {var retVal = parseInt(res.code);switch (retVal) {case 2:alert('输入有误');break;case 0:alert('注册失败');break;case 1:alert('注册成功!');location.href = '/login'                                break;case 10:alert('用户已注册');break;                         }}else {alert('操作失败');}},complete: function (XMLHttpRequest, textStatus) {},error: function (XMLHttpRequest, textStatus, errorThrown) {alert('操作失败');}});            })});</script>
reg.ejs

2.routes目录下reg.js

const router = require('koa-router')()
const userBll = require('./../pub/bll/userinfo.js')
const title = '注册'router.prefix('/reg')router.get('/', async (ctx, next) => {await ctx.render('reg', { title })
})router.post('/', async (ctx, next) => {let result = await userBll.register(ctx)ctx.body = result;})module.exports = router

登录

 1.views目录下login.ejs

<html>
<head>
<title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title>
</head>
<body>
<h1><%= title %></h1>
登录名:<input type="text" id="txtUserName" maxlength="20" />
<br/>
<br/>
密码:<input type="password" id="txtUserPwd" maxlength="12" />
<br/>
<br/>
<input type="button" id="btnSub" value="登录" />
</body>
</html><script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script>
<script src="/javascripts/md5.js" type="text/javascript"></script><script type="text/javascript">   $(function(){$('#btnSub').on('click', function(){var $txtUserName = $('#txtUserName'),txtUserNameVal = $.trim($txtUserName.val()),$txtUserPwd = $('#txtUserPwd'),txtUserPwdVal = $.trim($txtUserPwd.val());if(txtUserNameVal.length == 0){alert('用户名不能为空');                return false;}if(txtUserPwdVal.length == 0){                alert('密码不能为空');                return false;}$.ajax({url: '/login',type: 'POST',dataType: 'json',data: {username: txtUserNameVal,                    userpass: hex_md5(txtUserPwdVal)                                        },beforeSend: function (xhr) {},success: function (res) {if (res != null && res.code) {var retVal = parseInt(res.code);switch (retVal) {case 2:alert('输入有误');break;case 0:alert('登录失败');break;case 1:alert('登录成功!');location.href = '/'                                break;case 11:alert('用户名或者密码错误');break;case 12:alert('用户不存在');break;}}else {alert('操作失败');}},complete: function (XMLHttpRequest, textStatus) {},error: function (XMLHttpRequest, textStatus, errorThrown) {alert('操作失败');}});            })});</script>
login.ejs

 2.routes目录下login.js

const router = require('koa-router')()
const userBll = require('./../pub/bll/userinfo.js')
const title = '登录'router.prefix('/login')router.get('/', async (ctx, next) => {await ctx.render('login', { title })
})router.post('/', async (ctx, next) => {let result = await userBll.login(ctx);ctx.body = result;})module.exports = router

首页

 1.views目录下index.ejs

<html>
<head>
<title>Nodejs学习笔记(十五)--- Node.js + Koa2 构建网站简单示例</title>
</head>
<body>
<h1><%= title %></h1><% if(id != null) {%><h3>登录用户ID:<%= id %> <a id="btnLogOut" href="javascript:void(0);">安全退出</a></h3>
<% } %>
</body>
</html><script src="/javascripts/jquery-1.11.2.min.js" type="text/javascript"></script><script type="text/javascript">   $(function(){$('#btnLogOut').on('click', function(){if(!confirm('确认要退出吗?')){return;}$.ajax({url: '/logout',type: 'POST',dataType: 'json',data: {},beforeSend: function (xhr) {},success: function (res) {if (res != null && res.code) {var retVal = parseInt(res.code);switch (retVal) {                           case 0:alert('失败');break;case 1:alert('成功!');location.href = '/login'                                break;                           }}else {alert('操作失败');}},complete: function (XMLHttpRequest, textStatus) {},error: function (XMLHttpRequest, textStatus, errorThrown) {alert('操作失败');}});            })});</script>
index.ejs

 2.routes目录下index.js

const router = require('koa-router')()
const title = '首页'router.get('/', async (ctx, next) => {  //判断登录if(!ctx.session || !ctx.session.id){await ctx.redirect('/login')  }else{    const id = ctx.session.id;await ctx.render('index', { title, id })}  
})module.exports = router

 index.js文件中实现如果不存在session则跳回登录页

安全退出

 1.routes目录下logout.js

const router = require('koa-router')()
const retCode = require('./../pub/utils/retcode.js')router.prefix('/logout')router.get('/', async (ctx, next) => {await ctx.render('logout', {})
})router.post('/', async (ctx, next) => {ctx.session = null;let result = {code: retCode.Success,    data: null}ctx.body = result;})module.exports = router

写在之后

   没有去说一些细节API,写这篇主要可以对比 Nodejs学习笔记(七)--- Node.js + Express 构建网站简单示例 来看,完全是一亲的示例,只是这次用的Koa2,方便大家看看Koa2和express写出来的不同

   总的来说Koa2还是比较好上手,async、await这个对于有C#语言基础的来说也比较亲切,不用二次理解

   可以对比一下express时的各种嵌套回调写法,Koa2写好更优雅、更易阅读

 示例有限,其它操作通过官网查找API或github找一些组件来动手试,比如最常用的一些功能:操作cookies、上传文件、session存储到其它介质等

 

 参考资料: https://koa.bootcss.com/

 

 老规矩不放源码,虽然是示例结构,但是尽量按照平常做项目的想法去实现的,有兴趣的动手去搭项目做才会理解一些思路,代码都放在文章中了,有问题留言^_^!

转载于:https://www.cnblogs.com/zhongweiv/p/nodejs_koa2_webapp.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_901342.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BET365网站websocket解密分析

BET365网站websocket解密分析 ** 前不久和朋友聊到了这个网站,就手痒试了试,但是js解密有点不在行,所以只能去各种博客,github中寻找案例,然后自己在琢磨琢磨。 ** 本文仅用于交流学习 了解BET365网站的童鞋应该都知道它的更新频率是超快的, 这跟他使用的websocket数据…

BET365网站 2020-7 token生成分析

BET365网站 token生成分析 最近发现网站的js token生成逻辑变了&#xff0c;于是从新编辑一下&#xff0c;本篇只说思路&#xff0c;并无代码。 在以前生成token的位置打断点&#xff0c; 然后进行对比会发现这个token并无用处&#xff0c;已经成为一个障眼法了 然后我们根据某…

如何利用客户端缓存对网站进行优化?

介绍 你的网站在并发访问很大并且无法承受压力的情况下,你会选择如何优化? 很多人首先会想从服务器缓存方面着手对程序进行优化,许多不同的服务器缓存方式都有他们自己的特点,像我曾经参与的一些项目中,根据缓存的命中率不同使用过 Com/Enterprise Libiary Caching/Windows服…

如何查看sharepoint2013内所有的网站模板

我们可以在SharePoint 2013 Management powerShell中使用如下命令来获取Sharepoint的Site Template Lists Get-SPWebTemplate

将sharepoint 2013 网站集由基于路径命名转换到基于主机命名

由于一开始对sharepoint 了解不深&#xff0c;所以对基于路径和基于命令的网站集也了解不多&#xff0c;一开始创建网站集的时候全部创建成了基于路径的。再后来需要用到身份验证的时候&#xff0c;出现了很多问题&#xff0c;所以认真学习了一些基于主机命令的网站集创建方法&…

HelloGitHub.com 网站开源了

简介 随着 HelloGitHub 月刊持续更新了一年多&#xff0c;内容变的越来越多。因为内容数据没有结构化&#xff0c;如果还是使用之前的编辑文本的方式编辑月刊内容&#xff0c;会对后面的继续发刊和维护带来了很多问题和多余的工作&#xff0c;例如&#xff1a;查看、查重、分类…

常见的5种网站页面布局方式及特点分析

互联网的世界里&#xff0c;网页是我们接触最多的内容展示平台&#xff08;载体&#xff09;&#xff0c;各种风格设计及不同类型主题的网站数不胜数&#xff0c;笔者作为一名网页设计师&#xff0c;在关注内容本身的同时&#xff0c;也喜欢研究一下网站页面的设计特点&#xf…

地图网站,二三维地图

主要功能包括但不限于世界行政边界(简)、中国行政边界(简)、中国省级边界(简)、坐标定位、绘制采样、测量工具、计算投影代号、文件&#xff08;GEOJSON格式&#xff09;标注定位、图层管理&#xff08;包括近100种在线地图&#xff09;、腾讯街景、 路径规划&#xff08;步行&…

网站被反向代理方式镜像处理方法

现象: 通过对方域名访问网站内容和自己的一模一样,在自己空间新建一个文件,通过对方域名也能访问到 这种是对方通过反向代理方式实现了对自己网站文件的抓取甚至缓存到了对方服务器上,可找到对方代理服务器ip地址进行屏蔽 查找代理服务器ip: 在根目录建立一个123.php,写入<?…

tornado+bootstrap急速搭建你自己的网站

bootstrap既然是这么的流行又能省很多的事为什么不用他呢&#xff1f;再加上牛X的produced by FB的tornado简直如虎添翼了&#xff01; 1. 安装配置 安装所需要的库等内容。这里没什么需要多讲的。tornado直接用easy_install或者pip。bootstrap直接下下来就OK了。当然还需要下载…

使用Revel(go)开发网站

Revel很好的利用了Go语言的goroutine&#xff0c;把每一个request都分配到了goroutine里。不用再写一大堆的回调。如果你写过nodejs的话就会深刻的体会到callback hell是什么样子的。正是由于Revel有了goroutine&#xff0c;Revel的性能也有了很大的提升。官网号称请求的吞吐量…

【python】day10-14 flask框架——电影网站(持续更新中)

目录 1.新建项目 2.进行项目 1.新建readme.txt文件对整个项目进行文字说明 2.按照文字说明进行步骤 1.导入数据库 2.新建app包 3.新建manage.py文件 4.app包下 init.py文件添加代码 5.app包下 新建 admin包 6.templates文件夹下 新建admin包 7.设置修改运行的文件 8…

Linux安装apache、发布网站、修改端口、配置第二顺位默认发布文件

一、安装apache软件和手册 yum install httpd-y httpd-manual 二、发布网站 进入apache的/目录&#xff0c;默认发布目录 cd /var/www/html ##apache的/目录&#xff0c;默认发布目录 打开Xftp连接上自己主机&#xff0c;将要发布的网站文件从本地上次至服务器的/var/www/ht…

为自己的网站添加RSS功能

在浏览天极RSS订阅页面时&#xff0c;可以看到天极网为方便用户定制站点内容而设立的各个RSS频道。浏览者通过订阅不同的RSS(可同时订阅多个网站)&#xff0c;就能在不登录网站的情况下获得及时的新闻信息&#xff0c;还可以避免网页上无用的广告和垃圾信息的干扰。使用RSS会为…

推荐网站 explainshell.com

ls 显示指定目录下的文件和目录&#xff0c;默认为当前目录。 -a 显示所有文件及目录 (ls内定将文件名或目录名称开头为"."的视为隐藏档&#xff0c;不会列出) -l 除文件名称外&#xff0c;亦将文件型态、权限、拥有者、文件大小等资讯详细列出 -r 将文件以相反次序显…

[转老白]根据OSS帐号安装SAP Service网站证书

1、https://service.sap.com/support 2、点击&#xff1a;Quick Links 3、点击&#xff1a;/sso-smp 4、输入咪咪&#xff0c;点击“Apply for SAP Passport” 5、弹出几个消息框&#xff0c;一路YES下去就OK了 注:快捷连接 http://service.sap.com/sso-smp 080814213207.jpg 0…

Chineseocr在GPU上运行的问题及解决方法

Chineseocr在GPU上运行的问题及解决方法 - Sherrrry - 博客园 当yoloTextFlag keras GPUFalse出现如下错误&#xff1a; Tensors are unhashable. (KerasTensor(type_specTensorSpec(shape(None, None, None, 3), dtypetf.float32, nameinput_1), nameinput_1, description&qu…

scrapy+xpath爬取不可描述网站

今天来爬一个让人很有动力的网站&#xff0c;网址就不便放上来了&#xff0c;看看有没有有缘人能得知了 还是先来items.py import scrapyclass AvmooItem(scrapy.Item):# define the fields for your item here like:# name scrapy.Field()namescrapy.Field()birthdayscrapy…

Java学习练习成长系列网站(不是广告)

力扣&#xff08;LeetCode&#xff09; 这是一个非常非常Ok的网站&#xff0c;最大的亮点是有大量的代码题&#xff0c;个人认为力扣的编程题更偏向与算法和数据结构&#xff0c;当然基础题也是很多的&#xff0c;每天做3个&#xff0c;大约要一年才能做完&#xff0c;并且Visu…

免费采购网站 软件 平台大全 全国排行 必收藏

在电子商务蓬勃发展的今天&#xff0c;也促进了大量的采购平台的诞生&#xff0c;但也正是因为庞大的市场催生了出来了巨大的利益&#xff0c;使得很多不法采购平台非法攫取用户的利益。而同时很多正规的平台其数额不菲的入驻费也把很多中小企业拒之门外&#xff0c;那么小编将…