1 Introduction
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)
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
express
Adopt callback
to handle async, koa v1
adopt generator
, koa v2
adopt async/await
. generator
And async/await
use synchronous writing to deal with asynchronous, which is obviously better than callback
and promise
.
3.4 Middleware Model
express
Based on connect
middleware, linear model; koa
Middleware 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)
//同步
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
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
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/***.png
view 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.