共计 5534 个字符,预计需要花费 14 分钟才能阅读完成。
初始化项目
使用 koa-generator 脚手架工具
npm install koa-generator -g #全局安装
koa2 demo #创建 demo 项目
cd demo && npm install #安装依赖
默认生成项目结构如下
修改配置
用脚手架生成的项目,默认是服务器渲染,即响应的是 html 视图。而我们要开发接口,响应的是 json 数据。所以要删除渲染视图的代码。增加响应 json 的配置。
首先删除 views 文件夹,接下来就是修改 app.js
1. 删除视图配置
以下是要删除的代码
const views = require('koa-views')
app.use(views(__dirname + '/views', {extension: 'pug'}))
2. 修改路由的注册方式,通过遍历 routes
文件夹读取文件
const fs = require('fs')
fs.readdirSync('./routes').forEach(route=> {let api = require(`./routes/${route}`)
app.use(api.routes(), api.allowedMethods())
})
3. 添加 jwt 认证,同时过滤不需要认证的路由,如获取 token
const jwt = require('koa-jwt')
app.use(jwt({ secret: 'yourstr'}).unless({
path: [
/^\/$/, /\/token/, /\/wechat/,
{url: /\/papers/, methods: ['GET'] }
]
}));
4. 全局错误捕获并响应
// error
app.use(async (ctx, next) => {
try {await next()
} catch(err) {
ctx.status = err.statusCode || err.status || 500;
ctx.body = err.message
ctx.app.emit('error', err, ctx);
}
})
5. 跨域处理
当接口发布到线上,前端通过 ajax 请求时,会报跨域的错误。koa2 使用 koa2-cors
这个库非常方便的实现了跨域配置,使用起来也很简单
const cors = require('koa2-cors');
app.use(cors());
连接数据库
我们使用 mongodb 数据库,在 koa2 中使用 mongoose
这个库来管理整个数据库的操作。
1. 创建配置文件
根目录下新建 config 文件夹,新建mongo.js
// config/mongo.js
const mongoose = require('mongoose').set('debug', true);
const options = {autoReconnect: true}
// username 数据库用户名
// password 数据库密码
// localhost 数据库 ip
// dbname 数据库名称
const url = 'mongodb://username:password@localhost:27017/dbname'
module.exports = {connect: ()=> {mongoose.connect(url,options)
let db = mongoose.connection
db.on('error', console.error.bind(console, '连接错误:'));
db.once('open', ()=> {console.log('mongodb connect suucess');
})
}
}
然后在 app.js 中引入
const mongoConf = require('./config/mongo');
mongoConf.connect();
连接数据库完成!
2. Schema 和 Model
mongoose 有两个核心概念,Schema
和Model
。Schema 是预先定义的数据库模型骨架,定义集合存储的数据结构;Model 是依据 Schema 构造生成的模型,有数据库操作的能力。
下面是案例,新建一个用户集合:
根目录下新建 models 文件夹,新建 users.js
const mongoose = require('mongoose');
mongoose.Promise = global.Promise;
const Schema = mongoose.Schema
const ObjectId = mongoose.Types.ObjectId
// Schema
const usersSchema = new Schema({_id: { type: ObjectId}, // 默认生成,不加也可以
username: {type: String, required: [true,'username 不能为空'] },
sex: {type: String, enum: ['man','woman'], required: [true,'sex 不能为空'] },
age: {type: Number required: [true,'age 不能为空'] },
avatar: {type: String, default: ''}
})
// Model
const users = mongoose.model('users',usersSchema);
module.exports = users;
这样,一个用户集合的 model 就建好了,接下来在路由中直接引入这个 model,就可以进行数据库操作了
注册路由
按照 app.js 的配置,routes 文件夹下每一个文件都要注册成为一个路由
1. 基本结构
一个基本的, RESTful 风格的用户增查改删接口路由文件如下,包含了增查改删的通用写法
const router = require('koa-router')()
router.prefix('/users')
router.get('/', function (ctx, next) {ctx.body = '获取所有用户'})
router.get('/:id', function (ctx, next) {
let id = ctx.params.id
ctx.body = '获取单个用户'
})
router.post('/', function (ctx, next) {
let data = ctx.request.body
ctx.body = '新增用户'
})
router.put('/:id', function (ctx, next) {
let id = ctx.params.id
ctx.body = '修改用户信息'
})
router.delete('/:id', function (ctx, next) {
let id = ctx.params.id
ctx.body = '删除用户'
})
module.exports = router
2. 请求参数验证
任何一次请求接口传来的参数,首先要在最前面做一次参数验证。如果请求参数不合法,那么直接返回错误信息,无需继续走下面的业务逻辑。
参数验证,推荐使用 Joi 这个库,它是 hapijs 内置的参数验证模块,也是使用 Schema 定义数据结构。
比如创建用户接口,对用户传来的数据进行验证
const Joi = require('joi')
router.post('/', function (ctx, next) {
let data = ctx.request.body
let schema = Joi.object().keys({username: Joi.string().required(),
sex: Joi.string().required(),
age: Joi.number().required()
})
let result = Joi.validate(data, schema);
if(result.error) {return ctx.body = result.error.details}
let reqdata = result.value; #经过验证后的数据
})
这样就完成了一个简单的验证,具体验证请看 joi 文档
3. 数据库操作
之前已经创建了 users 的 model,现在我们可以直接在路由文件中使用该模块,进行数据库操作
// 引入上一步创建的 model
const Users = require('../models/users');
router.get('/', async (ctx, next)=> {ctx.body = await Users.find()
})
router.get('/:_id', async (ctx, next)=> {
let _id = ctx.params._id
ctx.body = await Users.findOne({_id})
})
// 创建用户
router.post('/', async (ctx, next)=> {
let data = ctx.request.body
ctx.body = await Users.create(data)
})
router.put('/:_id', async (ctx, next)=> {
let _id = ctx.params._id
let data = ctx.request.body
ctx.body = await Users.update({_id}, {$set: data}, {runValidators: true})
})
router.delete('/:_id', async (ctx, next)=> {
let _id = ctx.params._id
ctx.body = await Users.deleteOne({_id})
})
这是基本的增查改删的操作。这里用到了 koa2 最大的亮点,就是 async
,await
异步处理方案。只要 await 后面返回的是 promise,就可以直接使用。这比在 express 框架上使用 then 方法处理要优雅的多的多。
上一步讲的请求参数验证,是第一层验证。其实在 model 操作中,数据进入数据库时,也会进行一层验证,就是 mongoose 的 Schema 定义的数据类型和字段,如果不匹配,则会拒绝写入并返回错误。这就是 mongoose 的好处之一,可以防止写入不规范的数据。
这里不做 mongoose 的详解,附上文档地址:mongoose
运行与部署
1. pm2
应用启动文件是 www/bin
,所以我们可以通过 node www/bin
开启动应用,默认是 9000 端口。
这样启动会有一个问题,就是在修改代码之后,程序不会自动运行最新的代码,需要手动断开重新启动。
pm2 的诞生就是用来解决这个问题。他是一个 nodejs 应用程序管理器,通过 pm2 启动 nodejs 应用,开启监听模式,它就可以自动监听文件变化重启应用。
当然 pm2 的作用还有很多,首先启动应用:
pm2 start --name koa2 bin/www --watch
结果如下:
然后可以删除或重启:
pm2 list # 查看进程列表
pm2 restart koa2 # 重启名称为 koa2 的应用
pm2 delete koa2 # 删除名称为 koa2 的进程
pm2 logs koa2 # 查看名称为 koa2 的进程日志
2. nginx 配置
koa2 应用在 linux 服务端部署,首先需要 pm2 来启动应用。但是 koa2 项目启动一般不使用 80 端口,所以在线上部署时,还需要 nginx 做反向代理以及域名配置。
配置如下:
server {
listen 80;
server_name api.xxxxx.com;
location / {
proxy_pass http://127.0.0.1:9000;
#兼容 scoket.io
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
这样访问 api.xxxxx.com 就能访问 koa2 的应用了!
如果是https
,需要修改下配置:
server {
listen 80;
server_name api.xxxxx.com;
rewrite ^(.*) https://$host$1 permanent;
}
server {
listen 443 ssl;
server_name api.ruidoc.com;
ssl on;
ssl_certificate 1_api.xxxxx.com_bundle.crt; #ssl 证书
ssl_certificate_key 2_api.xxxxx.com.key;
location / {
proxy_pass http://127.0.0.1:9000;
#兼容 scoket.io
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
此时你可以上传你的应用了!
3. 快速上传源码
一般上传源码的时候,可能会用 ftp 服务之类的。如果是 Mac 用户,那么可以配置一条快捷命令,直接上传,方便省事
rsync -avz ./* root@1.23.45.67:/home/api
root 是服务器用户名;
1.23.45.67 是服务器 IP 地址;
/home/api 是源码在服务器的存放路径
然后输入服务器密码,就可以快速上传了,而且只会上传修改过的源码,非常快速。
还可以将命令配置到 package.json
文件的 scripts 下,如
"scripts": {"upload": "rsync -avz ./* root@1.23.45.67:/home/api"}
此时你可以这样上传:
npm run upload
这样配置上传效率非常高,一起试试吧!
本文由
杨成功
原创,更多原创文章关注 杨成功的全栈之路