版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_39197547/article/details/80997919
koa开发过程详解
第一步:安装koa和mongodb到项目中
1.首先在项目根目录下建立文件夹
service
,然后进入文件。
1
2
3
|
mkdir
service
cd
service
|
2.使用
npm init -y
生成并初始化package.json 文件。
3.在终端中使用npm来安装koa
npm
install
--
save
koa
|
|
index.js文件
const
Koa
=
require
(
'koa'
)
const
app
=
new
Koa
(
)
app
.
use
(
async
(
ctx
)
=
>
{
ctx
.
body
=
'<h1>hello Koa2</h1>'
}
)
app
.
listen
(
3000
,
(
)
=
>
{
console
.
log
(
'[Server] starting at port 3000'
)
}
)
MongoDB安装步骤
-
下载后进行安装,安装没什么难度,但是对于新手建议选择默认安装,而不选择自己配置。等我们完全熟悉后再定制式配置。
-
安装时如果有安全软件,会报一些拦截,一律允许就好,不允许会安装失败的。
-
安装完成后,需要配置“环境变量”,目的是再命令行中直接使用,而不需要输入很长的路径了。(此步骤观看视频)
运行MongoDB服务端
安装好MongoDB数据库后,我们需要启用服务端才能使用。启用服务的命令是:Mongod。
-
打开命令行:先打开运行(快捷键win+R),然后输入cmd后回车,就可以打开命令行工具。
-
执行mongod:在命令中直接输入mongod,但是你会发现服务并没有启动,报了一个exception,服务停止了。
-
新建文件夹:出现上边的错误,是因为我们没有简历Mongodb需要的文件夹,一般是安装盘的根目录,建立data/db,这两个文件夹。
-
运行mongod:这时候服务就可以开启了,链接默认端口是27017。
下载Robo3
由于我们是作项目,所以图形界面比较直观,我们上边并没有安装图形界面,这里我们使用Robo3来弥补一下。
然后就是下一步下一步安装了。
总结:这节课就是把MongoDB安装好,Koa2和MongoDB都安装好了,我们就可以愉快的编程了。
Koa用Mongoose连接数据库
Mongoose的安装
还是使用npm来进行安装。
1
2
|
npm
install
mongoose
--
save
|
连接数据库
我们在项目的
service
文件夹下建立一个
database
文件夹,用来存放和数据库操作有关的文件。在database文件夹下,建立一个
init.js
文件,用来作数据库的连接和一些初始化的事情。
/service/database/init.js
const
mongoose
=
require
(
'mongoose'
)
exports
.
connect
=
(
)
=
>
{
//连接数据库
mongoose
.
connect
(
db
)
let
maxConnectTimes
=
0
return
new
Promise
(
(
resolve
,
reject
)
=
>
{
//把所有连接放到这里
//增加数据库监听事件
mongoose
.
connection
.
on
(
'disconnected'
,
(
)
=
>
{
console
.
log
(
'***********数据库断开***********'
)
if
(
maxConnectTimes
<
3
)
{
maxConnectTimes
++
mongoose
.
connect
(
db
)
}
else
{
reject
(
)
throw
new
Error
(
'数据库出现问题,程序无法搞定,请人为修理......'
)
}
}
)
mongoose
.
connection
.
on
(
'error'
,
err
=
>
{
console
.
log
(
'***********数据库错误***********'
)
if
(
maxConnectTimes
<
3
)
{
maxConnectTimes
++
mongoose
.
connect
(
db
)
}
else
{
reject
(
err
)
throw
new
Error
(
'数据库出现问题,程序无法搞定,请人为修理......'
)
}
}
)
//链接打开的时
mongoose
.
connection
.
once
(
'open'
,
(
)
=
>
{
console
.
log
(
'MongoDB connected successfully'
)
resolve
(
)
}
)
}
)
}
然后在/service/index.js里加入立即执行函数,在使用前记得用require进行引入 connect。
//引入connect
const
{
connect
}
=
require
(
'./database/init.js'
)
//立即执行函数
;
(
async
(
)
=
>
{
await
connect
(
)
}
)
(
)
Mongoose的Schema建模介绍
数据库已经可以连接成功了,这节课学习一下如何建模,也就是定义Schema,他相当于MongoDB数据库的一个映射。Schema是一种以文件形式存储的数据库模型骨架,无法直接通往数据库端,也就是说它不具备对数据库的操作能力。Schema是以key-value形式Json格式的数据。
Schema中的数据类型
-
String :字符串类型
-
Number :数字类型
-
Date : 日期类型
-
Boolean: 布尔类型
-
Buffer : NodeJS buffer 类型
-
ObjectID : 主键,一种特殊而且非常重要的类型
-
Mixed :混合类型
-
Array :集合类型
Mongoose中的三个概念
-
schema :用来定义表的模版,实现和MongoDB数据库的映射。用来实现每个字段的类型,长度,映射的字段,不具备表的操作能力。
-
model :具备某张表操作能力的一个集合,是mongoose的核心能力。我们说的模型就是这个Mondel。
-
entity :类似记录,由Model创建的实体,也具有影响数据库的操作能力。
定义一个用户Schema
这节我们先以用户表为例,定义一个基本数据模型,当然这并不完善,我们会在后边的几节课把这个模型完善,并加入一些安全的机制进群。
在
/servcie/database/
文件夹下新建一个
schema
文件夹,然后新建一个
User.js
文件.
const
mongoose
=
require
(
'mongoose'
)
//引入Mongoose
const
Schema
=
mongoose
.
Schema
//声明Schema
let
ObjectId
=
Schema
.
Types
.
ObjectId
//声明Object类型
//创建我们的用户Schema
const
userSchema
=
new
Schema
(
{
UserId
:
ObjectId
,
userName
:
{
unique
:
true
,
type
:
String
}
,
password
:
String
,
createAt
:
{
type
:
Date
,
default
:
Date
.
now
(
)
}
,
lastLoginAt
:
{
type
:
Date
,
default
:
Date
.
now
(
)
}
}
)
//发布模型
mongoose
.
model
(
'User'
,
userSchema
)
载入Schema和插入查出数据
Schema建立好以后,需要我们载入这些数据库,当然最好的方法就是在后台服务已启动的时候就把载入做好,所以我们在service/init.js里作这件事,然后在index.js里直接执行。
载入所有Schema
直接在
service\init.js
先引入一个glob和一个resolve
首先安装glob
1
2
|
npm
install
glob
--
save
|
1
2
3
4
|
<
br
/
>
const
glob
=
require
(
'glob'
)
const
{
resolve
}
=
require
(
'path'
)
|
-
glob:node的glob模块允许你使用 * 等符号,来写一个glob规则,像在shell里一样,获取匹配对应规则文件。
-
resolve: 将一系列路径或路径段解析为绝对路径。
了解两个引入的模块用法后,我们就可以一次性引入所有的Schema文件了。
1
2
3
4
5
|
exports
.
initSchemas
=
(
)
=
>
{
glob
.
sync
(
resolve
(
__dirname
,
'./schema/'
,
'**/*.js'
)
)
.
forEach
(
require
)
}
|
使用了glob.sync同步引入所有的schema文件,然后用forEach的方法require(引入)进来。这比你一条条引入要优雅的多。
在操作数据库前先引入我们的Mongoose和我们刚写好的initSchemas:
1
2
3
|
const
mongoose
=
require
(
'mongoose'
)
const
{
connect
,
initSchemas
}
=
require
(
'./database/init.js'
)
|
我们直接在service/index.js的立即执行函数里插入一天User数据
;
(
async
(
)
=
>
{
await
connect
(
)
initSchemas
(
)
const
User
=
mongoose
.
model
(
'User'
)
let
oneUser
=
new
User
(
{
userName
:
'jspang'
,
password
:
'123456'
}
)
oneUser
.
save
(
)
.
then
(
(
)
=
>
{
console
.
log
(
'插入成功'
)
}
)
//读出已经插入进去的数据
let users = await User.findOne({}).exec()
console.log('------------------')
console.log(users)
console.log('------------------')
}
)
(
)
完整index.js
const
Koa
=
require
(
'koa'
)
const
app
=
new
Koa
(
)
const
mongoose
=
require
(
'mongoose'
)
const
{
connect
,
initSchemas
}
=
require
(
'./database/init.js'
)
//立即执行函数
;
(
async
(
)
=
>
{
await
connect
(
)
initSchemas
(
)
const
User
=
mongoose
.
model
(
'User'
)
let
oneUser
=
new
User
(
{
userName
:
'jspang13'
,
password
:
'123456'
}
)
oneUser
.
save
(
)
.
then
(
(
)
=
>
{
console
.
log
(
'插入成功'
)
}
)
let
users
=
await
User
.
findOne
(
{
}
)
.
exec
(
)
console
.
log
(
'------------------'
)
console
.
log
(
users
)
console
.
log
(
'------------------'
)
}
)
(
)
app
.
use
(
async
(
ctx
)
=
>
{
ctx
.
body
=
'<h1>hello Koa2</h1>'
}
)
app
.
listen
(
3000
,
(
)
=
>
{
console
.
log
(
'[Server] starting at port 3000'
)
}
)
打造安全的用户密码加密机制
加密处理
密码的加密有很多种加密算法,比如我们使用的MD5加密或者hash256加密算法,其实他们都是hash的算法。就是把你的密码进行一次不可逆的编译,这样就算别人得到了这个密码值,也不能进行直接登录操作。
加盐处理
有了加密的处理,我们的密码就安全多了,但是有用户的密码设置的太过简单,很好进行暴力破解或者用彩虹表破解,这时候感觉我们的密码又不堪一击了。这时候我们要使用加盐技术,其实就是把原来的密码里,加入一些其他的字符串,并且我们可以自己设置加入字符串的强度。
把加盐的数据库密码进行hash处理后,再存入数据库就比较安全了。
当然还有很多更严谨更可靠的加密机制,小伙伴可以自行探索一下,这个项目我们就是用加盐加密的方法处理用户的密码。
bcrypt的使用
简介:
bcrypt是一种跨平台的文件加密工具。bcrypt 使用的是布鲁斯·施内尔在1993年发布的 Blowfish 加密算法。由它加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符,并将在内部被转化为448位的密钥。
引入bcrypt
const
bcrypt
=
require
(
'bcrypt'
)
// 使用pre中间件在用户信息存储前进行密码加密23
UserSchema.pre('save',
function
(next){
24
var
user =
this
;
25
26
//
进行加密(加盐)
27
bcrypt.genSalt(SALT_WORK_FACTOR,
function
(err, salt){
28
if
(err){
29
return
next(err);
30
}
31
bcrypt.hash(user.password, salt,
function
(err, hash){
32
if
(err){
33
return
next(err);
34
}
35
user.password =
hash;
36
next();
37
})
38
});
39
});
Koa2的用户操作的路由模块化
所有的路由都写在
service/idnex.js
里显然不是正确的选择,这会导致我们的
index.js
页面越来越臃肿,最后变的没办法维护。我们需要把Koa程序模块化,我们也叫做路由模块化。
安装koa-router
npm
install
koa
-
router
--
save
新建一个User.js的文件
新建一个appApi的文件夹,然后在进入文件夹,新建User.js的文件。有关User.js的操作,我们以后都会放到这个文件下,就是要编写的供前台使用的接口程序了。
mkdir
appApi
cd
appApi
User.js
const
Router
=
require
(
'koa-router'
)
let
router
=
new
Router
(
)
router
.
get
(
'/'
,
async
(
ctx
)
=
>
{
ctx
.
body
=
"这是用户操作首页"
}
)
router
.
get
(
'/register'
,
async
(
ctx
)
=
>
{
ctx
.
body
=
"用户注册接口"
}
)
module
.
exports
=
router
;
让路由模块化
接下来,我们需要把这个文件和koa-router加入到
service/idnex.js
下面,实现可以访问。
1.首先在
index.js
的文件顶部,引入koa-router
1
2
|
const
Router
=
require
(
'koa-router'
)
|
2.引入我们的user.js模块
1
2
|
let
user
=
require
(
'./appApi/user.js'
)
|
3.装载所有子路由
1
2
3
|
let
router
=
new
Router
(
)
;
router
.
use
(
'/user'
,
user
.
routes
(
)
)
|
-
加载路由中间件
1
2
3
|
app
.
use
(
router
.
routes
(
)
)
app
.
use
(
router
.
allowedMethods
(
)
)
|
总结:
通过这种简单的模块化路由机制,我们就实现了文件的分离,
打通注册用户的前后端通讯
安装koa-bodyparser中间件
首先我们要接到前端发过来的请求,这时候需要安装
koa-bodyparser
中间件,我们使用npm来进行安装。
记得先进入到
service
目录下,在使用npm进行安装。
1
2
|
npm
install
--
save
koa
-
bodyparser
|
安装好后,在
service/index.js
文件中注册和引入中间件。
1
2
3
|
const
bodyParser
=
require
(
'koa-bodyparser'
)
app
.
use
(
bodyParser
(
)
)
;
|
serviceAPI.config.js接口配置文件
需要对接口配置文件作一些设置,加入我们的注册接口地址。
const
URL
=
{
getShoppingMallInfo
:
BASEURL
+
'index'
,
getGoodsInfo
:
BASEURL
+
'getGoodsInfo'
,
registerUser
:
LOCALURL
+
'user/register'
,
//用户注册接口
}
module
.
exports
=
URL
3.引入接口配置文件
1
2
|
import
url
from
'@/serviceAPI.config.js'
|
4.编写aixos用户注册方法
进入到
src/components/pages/Register.vue
文件下,在methods属性里,写入如下方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//*********axios注册用户方法********
axiosRegisterUser
(
)
{
axios
(
{
url
:
url
.
registerUser
,
method
:
'post'
,
data
:
{
username
:
this
.
username
,
password
:
this
.
password
}
}
)
.
then
(
response
=
>
{
console
.
log
(
response
)
}
)
.
catch
(
(
error
)
=
>
{
console
.
log
(
error
)
}
)
}
|
让koa2支持跨域请求
跨域对于新手小伙伴来说是个非常头疼的问题,在微信或者QQ群里很多小伙伴问我跨域的问题,当然跨域也有多种解决方案,但是个人认为最完美的解决方案是在后台设置支持跨域。对于这个项目后台就是我们的Koa2服务。
安装koa2-cors中间件
在koa2里解决跨域的中间件叫
koa2-cors
,我们先进入service文件夹,然后直接使用npm来进行安装。
npm
install
--
save
koa2
-
cors
记得要在
service/index.js
文件中引入和注册(使用)一下中间件:
1
2
3
|
const
cors
=
require
(
'koa2-cors'
)
app
.
use
(
cors
(
)
)
|
编写koa2接收前台数据的方法
这时候我们已经万事俱备了,打通了前台和后台数据互通的基本环节。现在主要开心的写一个后台的数据接口方法,就可以实现接收数据,并回传数据了。
进入
service/appApi/user.js
文件,修改resgister路由接口下的代码,记得把get方法换成post方法。
router
.
post
(
'/register'
,
async
(
ctx
)
=
>
{
console
.
log
(
ctx
.
request
.
body
)
ctx
.
body
=
ctx
.
request
.
body
}
)
Koa2的User.js 接口的完善
1.首先在
service/appApi/user.js
下引入mongose,这样就可以操作我们的Schema了。
1
2
|
const
mongoose
=
require
(
'mongoose'
)
|
2.编写 register接口的程序,代码的注释已经很详细,
router
.
post
(
'/register'
,
async
(
ctx
)
=
>
{
//取得Model
const
User
=
mongoose
.
model
(
'User'
)
//把从前端接收的POST数据封装成一个新的user对象
let
newUser
=
new
User
(
ctx
.
request
.
body
)
//用mongoose的save方法直接存储,然后判断是否成功,返回相应的结果
await
newUser
.
save
(
)
.
then
(
(
)
=
>
{
//成功返回code=200,并返回成功信息
ctx
.
body
=
{
code
:
200
,
message
:
'注册成功'
}
}
)
.
catch
(
error
=
>
{
//失败返回code=500,并返回错误信息
ctx
.
body
=
{
code
:
500
,
message
:
error
}
}
)
}
)
登录的服务端业务逻辑代码
需要在Shema中制作一个比对的实例方法,这个方法就是比对我们加盐加密后的密码的。在
service/database/schema/User.js
下增加下面的代码:
6
7
8
9
10
11
12
13
userSchema.methods = {
//密码比对的方法
comparePassword:(_password,password)=>{
return new Promise((resolve,reject)=>{
bcrypt.compare(_password,password,(err,isMatch)=>{
if(!err) resolve(isMatch)
else reject(err)
})
})
}
}
编写登录的Api接口
进入
service/appApi/user.js
,增加一个login路由,并在路由内写入业务逻辑代码。
/*登录的实践 */
router
.
post
(
'/login'
,
async
(
ctx
)
=
>
{
//得到前端传递过来的数据
let
loginUser
=
ctx
.
request
.
body
console
.
log
(
loginUser
)
let
userName
=
loginUser
.
userName
let
password
=
loginUser
.
password
//引入User的model
const
User
=
mongoose
.
model
(
'User'
)
//查找用户名是否存在,如果存在开始比对密码
await
User
.
findOne
(
{
userName
:
userName
}
)
.
exec
(
)
.
then
(
async
(
result
)
=
>
{
console
.
log
(
result
)
if
(
result
)
{
//console.log(User)
//当用户名存在时,开始比对密码
let
newUser
=
new
User
(
)
//因为是实例方法,所以要new出对象,才能调用
await
newUser
.
comparePassword
(
password
,
result
.
password
)
.
then
(
(
isMatch
)
=
>
{
//返回比对结果
ctx
.
body
=
{
code
:
200
,
message
:
isMatch
}
}
)
.
catch
(
error
=
>
{
//出现异常,返回异常
console
.
log
(
error
)
ctx
.
body
=
{
code
:
500
,
message
:
error
}
}
)
}
else
{
ctx
.
body
=
{
code
:
200
,
message
:
'用户名不存在'
}
}
}
)
.
catch
(
error
=
>
{
console
.
log
(
error
)
ctx
.
body
=
{
code
:
500
,
message
:
error
}
}
)