Koa and the Use of Common Middleware

Keywords: Database Session npm MySQL

1. What is Koa?

Node.js is an asynchronous world. The official API supports the asynchronous programming model in the form of callback, which brings many problems, such as nesting of callback, and the possibility of calling callback to return data synchronously in asynchronous functions, which may bring inconsistency. Koa appears to solve the above problems.

Koa is the next generation web development framework based on Node.js platform.

Koa was built by Express's original team and is committed to becoming a smaller, more expressive and more robust Web framework. Using Koa to write web applications can avoid the 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 very handy. The development idea is similar to Express. The biggest feature is that asynchronous nesting can be avoided.

 

2. Installation and Use of Koa Framework

Install Node.js version 7.6 or more

Before using Koa2 to develop, Node.js was required. It required Node.js version to be higher than V7.6, because Node.js 7.6 version began to fully support async/await, so we can fully support Koa2.

(2) Installation of Koa

npm install --save koa or cnpm install --save koa with Taobao mirror

(3) Basic use of Koa

// Introducing Koa
var koa = require('koa');
// Instantiation of Koa
var app = new koa();

// Configuration routing
app.use( async(ctx)=>{
    ctx.body = "Hello,koa"
});

// Monitor port
app.listen(3000);

 

3. Use of Async, Await and Proise in Koa Asynchronous Processing

Async is to make the method asynchronous. When you execute this code with node in the terminal, you will find that Promise {'Hello async'} is output, which returns Promise.

async function testAsync(){
    return 'Hello async';
};
const result = testAsync();
console.log(result);

// Promise { 'Hello async' }

Await is waiting for the async method to complete. Actually, await waits for only an expression, which in the official document refers to Promise objects, but it also accepts normal values. Note: await must be used in the async method, because the await access itself causes the program to stop blocking, so it must be used in the asynchronous method.

function getData() {
    return 'This is data';
};
async function testAsync() {
    return 'Hello async';
};
async function test() {
    // await returns a normal value
    const v1 = await getData();
    console.log(v1);
    // This is data

    // await returns promise object
    const v2 = await testAsync();
    console.log(v2);
    // Hello async
};
test();

To sum up, async is used to declare that a function is asynchronous. It encapsulates the return value of a subsequent function as a Promise object, while await is used to wait for an asynchronous method, Promise, to complete and return the result of its solution.

 

4. Use of Koa Routing

Routing in Koa is different from Express, which can be configured by introducing Express directly. But in Koa, we need to install the corresponding koa-router routing module.

// 1. Install npm install --save koa-router

var Koa = require('koa');

// 2. Introducing routing and instantiating
var router = require('koa-router')();
var app = new Koa();


// 3. Configuring routing
// Unlike Express, req and res, all information is put in ctx
router.get('/', async (ctx) => {
    // Return data
    // It is equivalent to res.write() and res.end() in native Node.js.
    ctx.body = "home page";

});

// 4. Start routing (from official documents);
// router.allowedMethods() can be configured or not.
// If the response header is not set before, the response header can be set automatically after configuring this option.
app.use(router.routes()).use(router.allowedMethods());


// Monitor port
app.listen(3000);

In addition, Koa's routing execution order is different from Express's. Koa chooses the onion ring model, which is the last response of the code after next() in the first route accessed.

The following code will be output in numbered order to illustrate the order in which the routing is executed.

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();

app.use(async (ctx, next) => {
    console.log('1.This is a middleware 01');
    await next();
    console.log('5.After matching the routing, it will return to execute the middleware.')
});
app.use(async (ctx, next) => {
    console.log('2.This is a middleware 02');
    await next();
    console.log('4.After matching the routing, it will return to execute the middleware.')
});                   
router.get('/news', async (ctx) => {
    console.log('3.Match up to news This routing');
    ctx.body = 'News page'
});


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

 

5.Koa Middleware

Middleware is a series of operations completed with routing matching. We can call it middleware. Using Middleware in Koa can achieve the following functions:

(1) Adding applications. app.use() is the main function to add or start some applications, such as the common use of third-party middleware.

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();

// Koa Application Level Middleware
app.use(async (ctx, next) => {
    // Print the date before matching the route
    console.log(new Date());
    // Continue downward matching after the current routing matching is completed
    // If you don't write next(), the route is matched and terminated.
    await next();
});

router.get('/news', async (ctx) => {
    ctx.body = 'News page'
});
// Start routing;
// router.allowedMethods() can be configured or not
// If no response header has been set before, the response header can be set automatically after configuring this option.
app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000);

(2) Matching routing. Multi-level routing matching is accomplished mainly through next().

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();

// Koa Routing Level Middleware

// Configuration of news pages
router.get('/news', async(ctx,next) => {
    console.log('This is news routing.');
    // Continue downward matching after matching to routing
    await next();
});

// Configuration of news pages
router.get('/news', async (ctx) => {
    ctx.body = 'This is the news page.'
});

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

app.listen(3000);

(3) Error handling. If the current access path is not matched downwards, the error response can be given through the middleware.

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();
// Koa error handling Middleware
// Whether app.use is placed before or after routing
// They all execute app.use before routing
app.use(async (ctx, next) => {
    console.log('This is a middleware');       // Execution order 1
    await next();
    if (ctx.status == 404) {           // Execution order 3
        ctx.body = 'This is a 404 page.';
    } else {
        console.log(ctx.url);
    }
});
// Configure news page//execution order 2
router.get('/news', async (ctx, next) => {
    console.log('This is news routing.');
    await next();
});

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

app.listen(3000);

 

6. Get transfer value and get get transfer value in Koa.

There are two main ways to get values in Koa:

(1) Key-value pair splicing is used to transfer parameters. The receiving parameters are mainly obtained by ctx.qruery. It should be noted that the same results can be obtained in CTX and ctx.request.

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();
// http://localhost:3000/news_details?id=123&author=aiguangyuan
router.get('/news_details',async(ctx)=>{

    // Reading Get Transfer Value from ctx

    console.log(ctx.url);
    // /news_details?id=123&author=aiguangyuan

    console.log(ctx.query);
    // { id: '123', author: 'aiguangyuan' }
    // Getting objects is the most common way

    console.log(ctx.querystring)
    // id=123&author=aiguangyuan
    // What you get is a string

    
    // Get the Get pass-through value from the request in ctx

    console.log(ctx.request.url);
    // /news_details?id=123&author=aiguangyuan

    console.log(ctx.request.query);
    // { id: '123', author: 'aiguangyuan' }

    console.log(ctx.request.querystring);
    // id=123&author=aiguangyuan

    ctx.body='News Details Page';
  
});

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

(2) Dynamic routing and receiving parameters are mainly obtained by ctx.params.

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();

// http://localhost:3000/news_details/123/456
router.get('/news_details/:aid/:cid', async (ctx) => {
    // Getting the transfer value of dynamic routing
    console.log(ctx.params);
    // { aid: '123' ,cid:'456'}
    ctx.body = 'News Details Page';

});

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

 

7. Getting the post value in Koa.

There are two main ways of post ing in Koa:

(1) Encapsulation of a native method for obtaining post parameters.

// Encapsulation method for obtaining post parameters
exports.getPostData = function (ctx) {
    // Getting asynchronous data
    return new Promise(function (resolve, reject) {
        try {
            let str = '';
            ctx.req.on('data', function (chunk) {
                str += chunk;
            });
            ctx.req.on('end', function (chunk) {
                resolve(str);
            });
        } catch (err) {
            reject(err);
        }
    })
};

Introduce encapsulation method to obtain data.  

var Koa = require('koa');
var router = require('koa-router')();
// Method of introducing encapsulation
var common = require('./module/common.js')
var app = new Koa();

// Receiving data submitted by post
router.post('/doAdd', async (ctx) => {
    // Data acquisition by encapsulation
    var data = await common.getPostData(ctx);
    console.log(data);
    // username=aiguangyuan&password=123456
    ctx.body = 'Add success';
});

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

(2) Use body-parser middleware to get post data.

// 1. Install NPM install -- save koa-body parser;

var Koa = require('koa');
var router = require('koa-router')();
// 2. Introducing Middleware
var bodyParser = require('koa-bodyparser'); 

var app = new Koa();
// 3. Configuring the middleware of body parser
app.use(bodyParser());

router.post('/doAdd', async (ctx) => {
    // 4. Obtain form submission data through ctx.request.body
    ctx.body=ctx.request.body;
    // {"username":"aiguangyuan","password ":"123456"}  
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000);

 

8. Use of Cookie in Koa

Cookie is saved in the browser client, which allows us to share data when the same browser accesses the same domain name. It can achieve the following functions.

(1). Save user information

(2) Browser history information

(3). Guess what you like about functions

(4) 10 days free of landing

(5) Data transfer between multiple pages

(6).cookie realizes shopping cart function

var Koa = require('koa');
var router = require('koa-router')();
var app = new Koa();

router.get('/', async (ctx) => {

    // Note that cookie s in koa cannot be set directly into Chinese

    // Using Buffer to Solve the Chinese Problem of Setting up cookie s
    var userinfo = new Buffer('Zhang San').toString('base64');

    // 1. Setting cookie s
    ctx.cookies.set('userinfo',userinfo ,{
        // Set the number of milliseconds that have expired
        maxAge: 60 * 1000 * 60,

        // The following parameters are not commonly used

        // Specific expiration time
        expires: '2019-1-1',
        // The path that cookie s can access by default is'/'
        path: '/',
        // The domain name that cookie s can access by default is all pages under the current domain name, unless there are multiple subdomains.
        domain: '',
        // Secure cookie, default false, set to true to indicate that only https can access it
        secure: false,
        // Is it just a server accessible cookie? The default is true
        httpOnly: true,
        // Whether to overwrite, default to false, not often used
        overwrite: false
    });
    ctx.body = "This is the front page.";
});

// Accessing cookie s in another route
router.get('/content', async (ctx) => {
    // 2. Get the set cookie and convert the cookie
    var data = ctx.cookies.get('userinfo');
    var userinfo = new Buffer(data,'base64').toString();

    console.log(userinfo);
    // Zhang San
    ctx.body = 'This is the content page.'
});

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

 

9. Use of Session in Koa

session is a mechanism for recording customer status. Compared with cookie s, they differ mainly in the following aspects:

(1) cookie data is stored on the client's browser and session data on the server.

(2) cookies are not very secure. Others can analyze cookies stored locally and cheat cookies. Considering security, session should be used.

(3) Session will be saved on the server for a certain period of time. When access increases, it will occupy the server. Considering the performance, cookie should be used.

(4) Data stored by a single cookie cannot exceed 4K, and many browsers limit a site to a maximum of 20 cookies.

// 1.npm install koa-session --save

var Koa = require('koa');
var router = require('koa-router')();

// 2. Introducing koa-session
var session = require('koa-session');
var app = new Koa();

// 3. Set the signature of cookie, you can set or default
app.keys=['some secret hurr']; 
// 4. Configuring session Middleware
var CONFIG = {
    key:'koa:sess',            // cookie key (default)
    maxAge:8600000,            // Cook expiration time (modification)          
    overwrite:true,            // Can override override (default)
    httpOnly:true,             // Is it available only to the server (default)
    signed:true,               // Signature (default)
    rolling:false,             // Update session every time you visit (default)
    renew:true                 // Update session near expiration time 
};

// 5. Enabling Middleware
app.use(session(CONFIG,app));

router.get('/login', async (ctx) => {
    // Setting session
    ctx.session.userinfo = 'Zhang San';
    ctx.body = "This is the login page.";
});

router.get('/', async (ctx) => {
    // Get session
    var userinfo = ctx.session.userinfo;
    console.log(userinfo);
    // Zhang San
    ctx.body = 'This is the front page.'
});

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

 

10. Acquisition of static resources in Koa

The static resource response in Koa is mainly realized through the middleware of Koa-static.

// 1.npm install koa-static --save

var Koa = require('koa');
var Router = require('koa-router');
var views = require('koa-views');

// 2. Introducing middleware for handling static resources
var static = require('koa-static');

var app = new Koa();
var router = new Router();
app.use(views('views', {
    extension: 'ejs'
}));
app.use(bodyParser());

// 3. Configuring the middleware of static web services;
// You can write more than one, find it in different directories
app.use(static(__dirname+'/static'));
app.use(static(__dirname+'/public'));

router.get('/', async (ctx) => {
    await ctx.render('login');
});

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

 

11. Using Ejs Template Engine in Koa

Ejs is a JavaScript template engine, which is used to render the database query data to the template and realize a dynamic website.

// 1.npm install koa-views --save
// 2.npm install ejs --save 

var Koa = require('koa');
var router = require('koa-router')();

// 3. Introducing koa-views
var views = require('koa-views');

var app = new Koa();


// 4. Configuring Template Engine Middleware
// The first parameter in views is the location of the template file
app.use(views('views', {
    // Using EJS template engine, template file ends with EJS
    extension: 'ejs'
}));

// It is also possible to configure the template engine in the following way
// app.use(views('views',{
//     Template files end in html
//     map:{ html:'ejs'}
// }));

// If we need to render a common data in every render of the route
// Common data needs to be placed in middleware so that it can be used anywhere in the template
app.use(async(ctx,next)=>{
    // userinfo can be used in any route
    ctx.state.userinfo ='Li Si';
    await next()
});


// Configure news page routing
router.get('/news', async (ctx) => {
    // Simulate the data from the database
    let list = [
        'Xi Da delivered a speech', 
        'Trump made a speech', 
        'Li Keqiang delivered a speech'
    ];
    let content="<h2>This is a H2</h2>";
    let num = 100;
    // 5. Rendering static pages
    await ctx.render('news', {
        list:list,
        content:content,
        num:num
    });

});

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

The common grammar of Ejs is as follows:

<!-- 1.Introducing Public Documents -->
<% include public/header.ejs%>

<!-- 2.Cyclic Rendering Data -->
<ul>
    <%for(var i=0;i<list.length;i++){%>
        <li><%=list[i]%></li>
    <%}%>
</ul>

<!-- 3.binding html data,No resolution -->
<%=content%>

<!-- 4.Rendering html Data and parsing -->
<%-content%>

<!-- 5.Conditional judgement -->
<% if(num==100){ %>
    <p>The current number equals 100</p>
<% }else{ %>
    <p>The current number is not equal to 100</p>
<% } %>

<!-- 6.Rendering all routing common data -->
<p><%=userinfo %></p>

 

12.Koa uses the Art-template template engine

Art-template is a simple, ultra-fast template engine. It optimizes the rendering speed of templates by using scope pre-declaration technology to achieve performance close to the JavaScript limit, while supporting NodeJS and browsers. Art-template supports Ejs grammar, and can also use a grammar similar to Angular data binding.

// 1. Installation module
// npm install --save art-template
// npm install --save koa-art-template

var Koa = require('koa');
var router = require('koa-router')();
var path = require('path');

// 2. Introducing Modules
var render = require('koa-art-template');
var app = new Koa();


// 3. Configuration module
render(app, {
    //  Position of View
    root: path.join(__dirname, 'views'),
    //  Suffix name
    extname: '.html',
    //  Whether to turn on debugging mode
    debug: process.env.NODE_ENV !== 'production'
});

router.get('/detail', async (ctx) => {
    // Simulate the data obtained from the database
    let data = { name: 'Li Si' };
    let text = '<span>This is a text.</span>';
    let num = 10;
    let list = ['List item 1','List item 2','List item 3'];

    // 4. Rendering data
    await ctx.render('detail', {
        data:data,
        text:text,
        num:num,
        list:list
    })
});

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

Ejs Writing of Art-template Template Engine.

<h1>Art-template Template Engine Ejs Writing method</h1>

<h2>1.Binding data</h2>
<span><%=data.name %></span>
<span><%=1+2 %></span>


<h2>2.binding html data</h2>
<span><%-text%></span>


<h2>3.conditional rendering</h2>
<% if(num>10){ %>
    <span>Size 10</span>
<% }else{ %>
    <span>Less than 10</span>
<%}%>


<h2>4.Circular data</h2>
<% for(var i=0;i<list.length;i++){ %>
    <p>
        <%=i%>--<%=list[i]%>
    </p>
<%}%>

<h2>5.Template introduction</h2>
<% include('./public/footer.html') %>

Angular Writing of Art-template Template Engine.

<h2>Art-template Template Engine Angular Writing method</h2>

<h2>1.Binding data</h2>
<span>{{data.name}}</span>
<span>{{1+2}}</span>


<h2>2.binding html data</h2>
<span>{{@text}}</span>


<h2>3.conditional rendering</h2>
{{ if num>10 }}
    <span>Size 10</span>
{{else}}
    <span>Less than 10</span>
{{/if}}


<h2>4.Circular data</h2>
{{each list}}
    <p>
        {{$index}}--{{$value}}
    </p>
{{/each}}


<h2>5.Template introduction</h2>
{{ include 'public/footer.html' }}

 

13. The use of Koa-multer, the middleware of Koa file upload

// 1.npm install  koa-multer --save

// 2. Introducing koa-multer
const multer = require('koa-multer');

const router = require('koa-router')();


// 3. Configure koa-multer; 
var storage = multer.diskStorage({
    // File save path
    destination: function (req, file, cb) {
        // Note that the path must exist
        cb(null, 'public/uploads')
    },
    // Modify the file name
    filename: function (req, file, cb) {
        var fileFormat = (file.originalname).split(".");
        // Picture name drops out after adding timestamp
        cb(null, Date.now() + "." + fileFormat[fileFormat.length - 1]);
    }
});

// 4. Load configuration
var upload = multer({ storage: storage });

// 5. Using upload, upload.single() stands for upload single, and the parameter is the name value of upload input.
router.post('/doAdd', upload.single('input-name-value'), async (ctx, next) => {
    ctx.body = {
        // Return file name
        filename: ctx.req.file.filename,
        body: ctx.req.body
    }
});

If you want to use a routing, so that multiple places share uploaded pictures, the routing can be configured as follows.

router.post('/doAdd', upload.fields([
        {
            // Upload form input value
            name: 'avatar',
            // Number
            maxCount: 1
        },
        {
            name: 'cover',
            maxCount: 2
        }
    ]),
    async (ctx, next) => {
        console.log(ctx.request.files);
        console.log(ctx.files);
        ctx.body = 'Upload success!';
    }
);

Notice that the form form is added with enctype="multipart/form-data"

 

13.Koa operates MySQL database

MySQL module is the engine for Node to operate MySQL. It can build tables, add, delete, change and check MySQL database in Node.js environment.

// 1.npm install --save mysql

// 2. Introducing Modules
const mysql = require('mysql');

// 3. Connecting to the database
const connection = mysql.createConnection({
    host: '127.0.0.1',         // Database Address
    user: 'root',              // User name 
    password: '123456' ,       // Password   
    database: 'my_data'        // Database name   
})

// 4. Execute sql statement to operate database
connection.query('SELECT * FROM user', (error, results, fields) => {
    if (error) {
        console.log(error)
    };
    // Operational data

    // Closing session
    connection.release();
});

Note that after the database session operation is completed, it needs to be closed to avoid occupying connection resources.

When multiple sessions need to operate on the database, in order to avoid reconnecting each session, a connection pool is needed to manage the session.

// 1.npm install --save mysql

// 2. Introducing Modules
const mysql = require('mysql');

// 3. Creating data pools
const pool = mysql.createPool({
    host: '127.0.0.1',         // Database Address
    user: 'root',              // User name 
    password: '123456',        // Password   
    database: 'my_data'        // Database name 
})

// 4. Session operation in data pool
pool.getConnection(function (err, connection) {
    // 5. Execute sql statement to operate database
    connection.query('SELECT * FROM user', (error, results, fields) => {
        
        // Execution operation

        // Release connection
        connection.release();
        // If there is a mistake, throw it
        if (error) {
            throw error;
        }
    })
})

 

14.Koa operates MongoDB database

MongoDB is a product between relational database and non-relational database, which has the most abundant functions and resembles relational database. The data structure he supports is very loose, so it can store more complex data types. Mongo's greatest feature is that the query language he supports is very powerful. Its grammar is somewhat similar to object-oriented query language. It can almost achieve most functions similar to single-table query in relational databases, and it also supports data indexing. It is characterized by high performance, easy deployment, easy use, and very convenient storage of data.

// 1.npm install mongodb --save

// 2. Introduce MongoClient under mongodb
var MongoClient = require('mongodb').MongoClient;

// 3. Define the address of the database connection and configure the database
var url = 'mongodb://localhost:27017/';
var dbName = 'koa';


// 4. Connecting to the database
MongoClient.connect(url, function (err, client) {
    const db = client.db(dbName); 
});

// 5. Operating database
MongoClient.connect(url, function (err, db) {
    db.collection('user').insertOne({ "name": "Lucy" },function (err, result){
        // Judge whether the addition is successful

        // close database
        db.close(); 
    })
})

 

Posted by jsim on Mon, 16 Sep 2019 20:25:15 -0700