[Nodejs] Basic use of Koa

1 Introduction

image-20221231151037428
Koa was built by the original Express team, and is committed to becoming a smaller, more expressive, and more robust Web framework. Using koa to write web applications, by combining different generators, can avoid repeated and tedious nesting of callback functions, and greatly improve the efficiency of error handling. Koa does not bind any middleware in the kernel method, it only provides a lightweight and elegant function library, which makes writing web applications handy.

2. Quick start

2.1 Install koa2

# 初始化package.json
npm init
# 安装koa2 
npm install koa

2.2 hello world code

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

app.use( async ( ctx ) => {
  ctx.body = 'hello koa2' //json数据
})

app.listen(3000)

image-20220417092053231

2.3 start

node index.js

3. koa vs express


It is usually said that Koa is an onion model, which focuses on the design of middleware. But according to the above analysis, you will find that Express is similar, the difference is that the Express middleware mechanism uses Callback implementation, so if there is asynchrony, it may confuse you in the order of execution, so if we want to do interface time-consuming statistics , error handling Koa's middleware pattern is more convenient to handle. The last point of the response mechanism is also very important. Koa does not respond immediately, but responds at the outermost layer after the entire middleware processing is completed, while Express responds immediately.

3.1 Lighter

  • koa does not provide built-in middleware;
  • Koa does not provide routing, but separates the routing library (koa/router)

3.2 Context object

Koa adds a Context object as the context object of this request (passed in as the first parameter of the middleware in koa2). At the same time, two objects, Request and Response, are also mounted on the Context. Similar to Express, both objects provide a large number of convenient methods to assist development, so it becomes more reasonable to save some public parameters

3.3 Asynchronous process control

expressAdopt callbackto handle async, koa v1adopt generator, koa v2adopt async/await. generatorAnd async/awaituse synchronous writing to deal with asynchronous, which is obviously better than callbackand promise.

3.4 Middleware Model

​ expressBased on connectmiddleware, linear model; koaMiddleware adopts the onion model (for each middleware, after completing some things, it can very elegantly pass control to the next middleware, and can wait for it to complete, when the subsequent After the middleware finishes processing, control returns to itself)

image-20220417083817823

image-20220417085913567

//同步
var express = require("express")
var app = express()

app.use((req,res,next)=>{
    
    
    console.log(1)
    next()
    console.log(4)
    res.send("hello")
})
app.use(()=>{
    
    
    console.log(3)
})

app.listen(3000)

//异步
var express = require("express")
var app = express()

app.use(async (req,res,next)=>{
    
    
    console.log(1)
    await next()
    console.log(4)
    res.send("hello")
})
app.use(async ()=>{
    
    
    console.log(2)
    await delay(1)
    console.log(3)
})

function delay(time){
    
    
 return new Promise((resolve,reject)=>{
    
    
    setTimeout(resolve,1000)
 })
}
//同步
var koa = require("koa")
var app = new koa()

app.use((ctx,next)=>{
    
    
    console.log(1)
    next()
    console.log(4)
    ctx.body="hello"
})
app.use(()=>{
    
    
    console.log(3)
})

app.listen(3000)

//异步
var koa = require("koa")
var app = new koa()

app.use(async (ctx,next)=>{
    
    
    console.log(1)
    await next()
    console.log(4)
    ctx.body="hello"
}) 
app.use(async ()=>{
    
    
    console.log(2)
    await delay(1)
    console.log(3)
})

function delay(time){
    
    
 return new Promise((resolve,reject)=>{
    
    
    setTimeout(resolve,1000)
 })
}

app.listen(3000)

4. Routing

4.1 Basic use

var Koa = require("koa")
var Router = require("koa-router")

var app = new Koa()
var router = new Router()

router.post("/list",(ctx)=>{
    
    
    ctx.body=["111","222","333"]
})
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)

4.2 router.allowedMethods role

image-20220417102845079

4.3 Request method

Koa-router request methods: get , put , post , patch , delete , del , and the usage method is router.method(), such as router.get() and router.post(). And router.all() will match all request methods.

var Koa = require("koa")
var Router = require("koa-router")

var app = new Koa()
var router = new Router()

router.get("/user",(ctx)=>{
    
    
    ctx.body=["aaa","bbb","ccc"]
})
.put("/user/:id",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"user update"}
})
.post("/user",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"user post"}
})
.del("/user/:id",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"user del"}
})


app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)

4.4 Split Routing

routes/list.js

var Router = require("koa-router")
var router = new Router()
router.get("/",(ctx)=>{
    
    
    ctx.body=["111","222","333"]
})
.put("/:id",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"list update"}
})
.post("/",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"list post"}
})
.del("/:id",(ctx)=>{
    
    
    ctx.body={
    
    ok:1,info:"list del"}
})
module.exports = router
routes/index.js

var Router = require("koa-router")
var user = require("./user")
var list = require("./list")

var router = new Router()

router.use('/user', user.routes(), user.allowedMethods())
router.use('/list', list.routes(), list.allowedMethods())

module.exports = router
entry入口

var Koa = require("koa")
var router = require("./routes")

var app = new Koa()
app.use(router.routes()).use(router.allowedMethods())
app.listen(3000)

4.5 Routing prefix

router.prefix('/api')
router.use('/user', user.routes(), user.allowedMethods())

4.6 Routing Redirection

router.get("/home",(ctx)=>{
    
    
    ctx.body="home页面"
})

//写法1 
router.redirect('/', '/home'); //匹配到/重定向到/home
//写法2
router.get("/",(ctx, next)=>{
    
    
    ctx.redirect("/home")
})

5. Static resources


const Koa = require('koa')
const path = require('path')
const static = require('koa-static')

const app = new Koa()

app.use(static(path.join( __dirname,  "public")))

app.use( async ( ctx ) => {
    
    
  ctx.body = 'hello world'
})

app.listen(3000)

6. Get request parameters


6.1 Get parameters

In koa, the data source for GET request is the query method or querystring method in the request object in koa.

query returns a formatted parameter object, and querystring returns a request string. Since ctx directly refers to the request API, there are two ways to obtain GET request data.

  • Obtain the request object ctx.query directly from the context, return such as { a:1, b:2 } request string ctx.querystring, return such as a=1&b=2
  • Obtain the request object ctx.request.query from the request object of the context, return such as { a:1, b:2 } request string ctx.request.querystring, return such as a=1&b=2

6.2 post parameters

For the processing of POST requests, the koa-bodyparser middleware can parse the formData data of the koa2 context into ctx.request.body

const bodyParser = require('koa-bodyparser')

// 使用ctx.body解析中间件
app.use(bodyParser())

7. ejs template


7.1 Installing modules

# 安装koa模板使用中间件
npm install --save koa-views
# 安装ejs模板引擎
npm install --save ejs

7.2 Using template engines

File Directory

├── package.json
├── index.js
└── view
    └── index.ejs

./index.js file

const Koa = require('koa')
const views = require('koa-views')
const path = require('path')
const app = new Koa()

// 加载模板引擎
app.use(views(path.join(__dirname, './view'), {
    
    
  extension: 'ejs'
}))

app.use( async ( ctx ) => {
    
    
  let title = 'hello koa2'
  await ctx.render('index', {
    
    
    title: 'hello world',
  })
})

app.listen(3000)

./view/index.ejs template

<!DOCTYPE html>
<html>
<head>
    <title><%= title %></title>
</head>
<body>
    <h1><%= title %></h1>
    <p>EJS Welcome to <%= title %></p>
</body>
</html>

8. cookie&session


8.1 cookie

Koa provides methods to read and write cookies directly from the context

  • ctx.cookies.get(name, [options]) read the cookie in the context request
  • ctx.cookies.set(name, value, [options]) write cookie in context

8.2 session

  • koa-session-minimal is a session middleware for koa2, providing a read-write interface for storage media.
const session = require('koa-session-minimal')

app.use(session({
    
    
    key: 'SESSION_ID',
    cookie: {
    
    
        maxAge:1000*60
    }
}))
app.use(async (ctx, next) => {
    
    
    //排除login相关的路由和接口
    if (ctx.url.includes("login")) {
    
    
        await next()
        return
    }

    if (ctx.session.user) {
    
    
        //重新设置sesssion
        ctx.session.mydate = Date.now()
        await next()
    } else {
    
    
        ctx.redirect("/login")
    }
})

9. Upload pictures


9.1 Environment

  • koa: used to start a web server
  • koa2-cors: solve cross-domain problems
  • koa-router: koa routing processing
  • koa-body: acquisition of koa parameters
  • koa-static: static resource configuration
  • @koa/multer and multer: plugin for image upload

9.2 Code structure

image-20221231153921717

9.3 Implementation

  • Step 1: Build a simple web service with koa+koa-router
//main.js
const Koa = require('koa') // 引入koa
const Router = require('koa-router') // 引入koa-router
const {
    
     koaBody } = require('koa-body');

var router = new Router()

router.get('/', async (ctx) => {
    
    
    ctx.type = 'html'
    ctx.body = '<h1>hello world!</h1>'
}).post('/upload', async (ctx) => {
    
    
    ctx.body = 'ok'
})

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

app.listen(3000)

Now we can open http://localhost:3000 to see hello world

  • Then we create a new upload folder, and add the code of static content to the code
//mian.js 新增代码
const static = require('koa-static')
const path = require('path')

app.use(router.routes())
    .use(router.allowedMethods())
    .use(static(path.join(__dirname, './upload')))

At this point, if you add a new photo in the upload folder, you can http://localhost:3000/***.pngview it through . (***: Add suffix to the name of the photo you added yourself)

  • At this point, add an index.html file and add the following code
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <input type="file" class="file" name="avatar">
  <button onclick="send()">上传</button>
  
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script>
    let formData = new FormData()
    
    document.querySelector('.file').addEventListener('change', function(e) {
      
      
          let files = e.target.files
          console.log(files)
          if (!files.length) return
          formData.append('file', files[0], files[0].name)
        })
    
        function send(){
      
      
          axios.post('http://localhost:3000/upload',formData,{
      
      
            Headers:{
      
      
              "Content-type":"multipart/form-data"
            }
          })
        }
  </script>
</body>
</html>

If you select a picture and upload it, you will find that there is a cross-domain problem, then if you find the problem and solve the problem, directly upload the code:

//mian.js新增代码
const cors = require('koa2-cors')

//注意这个配置要在router前使用不然不生效
app.use(cors())
    .use(koaBody())
    .use(router.routes())
    .use(router.allowedMethods())
    .use(static(path.join(__dirname, './upload')) )

After solving the cross-domain, select the picture and upload it. At this time, we have got the passed data, and the main event is coming: @koa/multer uses

const multer = require('@koa/multer')
const storage = multer.diskStorage({
    
    
    destination: function (req, file, cb) {
    
    
        cb(null, './upload')
    },
    filename: function (req, file, cb) {
    
    
        const fileFormat = (file.originalname).split('.')
        cb(null, Date.now() + '.' + fileFormat[fileFormat.length - 1])
    }
})
const upload = multer({
    
     storage })

Modify /upload after configuration

router.post('/upload', upload.single('file'), async (ctx) => {
    
    
    console.log('ctx.file',  ctx.file)
})

Note: It should be noted that the file in upload.single('file') needs to be consistent with the formData field in the index.html above. At this time, you can upload happily~~~

10. Logging


const Koa = require('koa')
const Router = require('koa-router')
// 引入 koa-logger
const logger = require('koa-logger')

const app = new Koa()
const router = new Router()
// 使用 koa-logger 中间件
app.use(logger((str, args) => {
    
    
  // console.log(str);
  // console.log(args);
}))

router.get('/', ctx => {
    
    
  ctx.body = '首页'
})

// 使用路由中间件
app.use(router.routes())

app.listen(3000, () => {
    
    
  console.log('listen 3000 ok');
})
  • A function can be passed when registering the koa-logger middleware, which has 2 parameters
  • str is a string type. When a request occurs, str contains request type and request path information. When a response occurs, str contains response status code, response duration, and response file size information.
  • args is an array type. When a request occurs, the request type and request path will be placed in the array. When a response occurs, the response status code, response duration, and response file size information will be placed in the array.

Guess you like

Origin blog.csdn.net/weixin_43094619/article/details/131939319