0
点赞
收藏
分享

微信扫一扫

Node.js中利用Koa创建Web服务器、编写接口

王老师说 2022-04-25 阅读 85
node.js

Koa(koa.js)中文网 -- 基于 Node.js 平台的下一代 web 开发框架koa (koajs)是由 Express 原班人马打造的,致力于成为一个更小、更富有表现力、更健壮的 Web 框架。使用 koa 编写 web 应用,通过组合不同的 generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理的效率。https://www.koajs.com.cn/

1. 创建基本的Web服务器

# 在项目中下载koa包
npm i koa
//1、导入koa
const Koa=require('koa')
//2、创建Web服务器
const app=new Koa()

//第一个中间件
app.use(async(ctx,next)=>{
    await next()
    console.log('再打印第一个中间件')
    ctx.body='Hello world'
})
//第二个中间件
app.use(async(ctx)=>{
    console.log('先打印第二个中间件')
})

//3、启动Web服务器,调用app.listen(端口号,启动成功后的回调函数)
app.listen(3000)

2. 路由

路由是客户端的请求与服务器处理函数之间的映射关系。

(1)使用原生方法实现路由:不够简洁,优雅!

//1、导入koa
const Koa = require('koa')
//2、创建Web服务器
const app = new Koa()

//路由中间件
app.use(async (ctx) => {
    if (ctx.url === '/') {
        ctx.body = 'Home Page'
    } else if (ctx.url === '/users') {
        if (ctx.method === 'GET') {
            ctx.body = 'Users Page'
        } else if (ctx.method === 'POST') {
            ctx.body = 'Create New User'
        } else {
            ctx.status = 405 //Not allowed
        }
    } else if (ctx.url.match(/\/users\/\w+/)) { //用户id由字母数字组成
        if (ctx.method === 'GET') {
            // macth()返回的数组第一项为整个url,在正则表达式中给我们需要的信息加上小括号,数组第二项就为我们需要的信息
            const userId = ctx.url.match(/\/users\/(\w+)/)[1] //获取数组第二项的userId
            ctx.body = `用户id为${userId}`
        } else {
            ctx.status = 405 //Not allowed
        }
    } else {
        ctx.status = 404 //Not Found
    }
})

//3、启动Web服务器,调用app.listen(端口号,启动成功后的回调函数)
app.listen(3000)

(2)使用koa-router实现路由:

# 在项目中下载koa-router包
npm i koa-router
# 解析请求体的包
npm i koa-bodyparser
const Koa = require('koa')
const app = new Koa()
// 1、引入koa-router
const Router = require('koa-router')
// 2、创建路由
const router = new Router() //配置无路由前缀的路由
const usersRouter = new Router({ //配置路由前缀为users的路由
    prefix: '/users'
})

// 解析请求体
const bodyparser = require('koa-bodyparser') // 引入koa-bodyparser
app.use(bodyparser()) // 注册

// 安全中间件
const auth = async (ctx, next) => {
    if (ctx.url !== '/users') {
        ctx.throw(401) //Unauthorized
    }
    await next()
}

// 虚拟数据
const db = [{
    name: '小明',
    age: '13',
    sex: '男'
}, {
    name: '小红',
    age: '15',
    sex: '女'
}]

// 3.挂载路由
router.get('/', (ctx) => { // 首页
    ctx.body = '<h1>Home Page</h1>'
})
usersRouter.get('/', auth, (ctx) => { // 查列表
    ctx.set('Allow', 'GET,POST') // 设置响应头Headers
    ctx.body = db
})
usersRouter.get('/:id', (ctx) => { // 查一个
    if (ctx.params.id >= db.length) {
        ctx.throw(412, '先决条件错误,id大于数组长度')
    }
    ctx.body = db[ctx.params.id] // 假设id为数据索引
})
usersRouter.post('/', (ctx) => { // 增
    // 要新增的数据通过请求体传递过来
    db.push(ctx.request.body)
    ctx.body = ctx.request.body
})
usersRouter.put('/:id', (ctx) => { // 改
    // 要修改为的数据通过请求体传递过来
    db[ctx.params.id] = ctx.request.body
    ctx.body = ctx.request.body
})
usersRouter.delete('/:id', (ctx) => { // 删
    db.splice(ctx.params.id, 1) // 假设id为数据索引
    ctx.status = 204 // No content
})
// 4.注册路由中间件
app.use(router.routes())
app.use(usersRouter.routes())
// allowedMethods作用:
//(1)响应options请求,返回支持的请求方法
//(2)返回405表示不允许访问,返回501表示方法还没实现
app.use(usersRouter.allowedMethods())

app.listen(3000)

(3)模块化路由:将路由抽离为单独的模块,与控制器分离【推荐使用!】

入口文件index.js:

// index.js

const Koa = require('koa')
const app = new Koa()

const bodyparser = require('koa-bodyparser')
app.use(bodyparser()) 

const router=require('./routes/home.js')
const usersRouter=require('./routes/users.js')

app.use(router.routes())
app.use(usersRouter.routes())
app.use(usersRouter.allowedMethods())

app.listen(3000,()=>{
    console.log('koa server running at http://127.0.0.1:3000')
})

 路由放在routes文件夹中:

// /routes/home.js

const Router = require('koa-router')
const router = new Router()
const { index } = require('../controllers/home.js')

router.get('/', index)

module.exports = router
// /routes/users.js

const Router = require('koa-router')
const usersRouter = new Router({ //配置路由前缀为users的路由
    prefix: '/users'
})
const {getUserList,findUserById,createUser,updateUserById,deleteUserById}=require('../controllers/users.js')

usersRouter.get('/', getUserList)
usersRouter.get('/:id', findUserById)
usersRouter.post('/', createUser)
usersRouter.put('/:id', updateUserById)
usersRouter.delete('/:id', deleteUserById)

module.exports=usersRouter

控制器放在controllers文件夹中:

// /controllers/home.js

class HomeCtrl{
    index(ctx){
        ctx.body = '<h1>Home Page</h1>'
    }
}

module.exports=new HomeCtrl()
// /controllers/users.js

// 虚拟数据
const db = [{
    name: '小明',
    age: '13',
    sex: '男'
}, {
    name: '小红',
    age: '15',
    sex: '女'
}]

class UsersCtrl{
    getUserList(ctx){
        ctx.set('Allow', 'GET,POST') // 设置响应头Headers
        ctx.body = db
    }
    findUserById(ctx){
        if (ctx.params.id >= db.length) {
            ctx.throw(412, '先决条件错误,id大于数组长度')
        }
        ctx.body = db[ctx.params.id] // 假设id为数据索引
    }
    createUser(ctx){
        db.push(ctx.request.body)
        ctx.body = ctx.request.body
    }
    updateUserById(ctx){
        db[ctx.params.id] = ctx.request.body
        ctx.body = ctx.request.body
    }
    deleteUserById(ctx){
        db.splice(ctx.params.id, 1) // 假设id为数据索引
        ctx.status = 204 // No content
    }
}

module.exports=new UsersCtrl()

3. 异常处理

1. 状态码Status:

(1)正常:返回200。

(2)运行时错误:返回500。

(3)逻辑错误:无法找到,返回404。先决条件错误,返回412。参数格式错误,返回422。

2. 使用 koa-json-error 进行异常处理:

使用 koa-json-error 进行异常处理,返回值为json格式。

# 在项目中下载koa-json-error包
npm i koa-json-error

3. 使用 koa-parameter 校验参数是否正确:

使用 koa-parameter 校验参数是否正确,返回值为json格式。

# 在项目中下载koa-parameter包
npm i koa-parameter
// 入口文件 index.js

const Koa = require('koa')
const app = new Koa()
const bodyparser = require('koa-bodyparser')
app.use(bodyparser())

// 1.自己编写的异常处理中间件
// app.use(async (ctx, next) => {
//     try {
//         await next()
//     } catch (err) {
//         ctx.status = err.status || err.statusCode || 500
//         // 返回的错误信息最好是json格式
//         ctx.body = {
//             message: err.message
//         }
//     }
// })

// 2.使用koa-json-error中间件进行异常处理
const error = require('koa-json-error')
app.use(error({
    // development环境下返回错误栈stack,production环境下不返回错误栈stack
    postFormat: (e, {stack,...rest}) => process.env.NODE_ENV === 'production' ? rest : {stack,...rest}
}))

// 3.使用koa-parameter中间件校验参数格式是否正确
const parameter = require('koa-parameter')
app.use(parameter(app)) // app参数使koa-parameter可以全局使用

const router = require('./routes/home.js')
const usersRouter = require('./routes/users.js')

app.use(router.routes())
app.use(usersRouter.routes())
app.use(usersRouter.allowedMethods())

app.listen(3000, () => {
    console.log('koa server running at http://127.0.0.1:3000')
})

koa-parameter可以全局使用:

// /controllers/users.js 中部分关键代码
// koa-parameter的全局使用方法

    createUser(ctx) {
        // 参数校验
        ctx.verifyParams({
            name: {
                type: 'string',
                required: true
            },
            age: {
                type: 'number',
                required: false
            }
        })
        db.push(ctx.request.body)
        ctx.body = ctx.request.body
    }

注意:若要使用process.env.NODE_ENV判断当前程序运行环境是开发环境还是生产环境,可以在package.json文件中进行配置。

模拟node.js项目在生产环境中运行:

npm start

 模拟node.js项目在开发环境中运行:

npm run dev

 

举报

相关推荐

0 条评论