brief introduction
Koa It's a simple and easy-to-use Web framework. It is characterized by elegance, conciseness, strong expression and high degree of freedom. The code itself is only over 1000 lines, and all functions are implemented through plug-ins.
Pre-school preparation
Check the Nodejs version
Open the cmd command line window node-v
Note: Koa must use version 7.6 or more. If your version is below this requirement, upgrade Node first.
Supporting cases
I. Basic Usage
1.1 Three lines of code to set up HTTP services
npm install koa
const Koa = require('koa'); const app = new Koa(); app.listen(3000);
1.2 Context object
Koa provides a Context object that represents the context of a conversation (including HTTP requests and HTTP replies). By processing this object, you can control the content returned to the user.
The Context object contains:
const Koa = require('koa') const app = new Koa() app.use((ctx, next) => { //ctx is the context of the entire application, including commonly used request s, response s //ctx.response stands for HTTP Response. Similarly, ctx.request represents HTTP Request. //ctx.response.body can be abbreviated as ctx.body. ctx.response.body = 'hello world' }) app.listen(3000)
1.3 Types of HTTP Response
Koa's default return type is text/plain. If you want to return other types of content, you can first use ctx.request.accepts to determine what data the client wants to accept (according to the Accept field of HTTP Request), and then use ctx.response.type to specify the return type.
const Koa = require('koa') const app = new Koa() //Declare a main middleware. If you are eager to understand the middleware, you can jump to (3) const main = (ctx,next) =>{ if (ctx.request.accepts('json')) { ctx.response.type = 'json'; ctx.response.body = { data: 'Hello World' }; } else if (ctx.request.accepts('html')) { ctx.response.type = 'html'; ctx.response.body = '<p>Hello World</p>'; } else if (ctx.request.accepts('xml')) { ctx.response.type = 'xml'; ctx.response.body = '<data>Hello World</data>'; } else{ ctx.response.type = 'text'; ctx.response.body = 'Hello World'; }; }; //The json format is displayed on the direct running page, because we do not set the request header, so each format is ok. app.use(main)//app.use() is used to load middleware. app.listen(3000)
1.4 Page Template
In actual development, web pages returned to users are often written as template files. We can let Koa read the template file first, and then return the template to the user.
const fs = require('fs'); const Koa = require('koa'); const app = new Koa(); const main = ctx => { ctx.response.type = 'html'; ctx.response.body = fs.createReadStream('./data/index.html'); }; app.use(main); app.listen(3000);
Two, routing
2.1 Native Routing
const Koa = require('koa') const app = new Koa() app.use((ctx, next) => { if (ctx.request.url == '/') {//Get the user request path through ctx.request.url ctx.body = '<h1>home page</h1>' } else if (ctx.request.url == '/my') { ctx.body = '<h1>Contact us</h1>' } else { ctx.body = '<h1>404 not found</h1>' } }) app.listen(3000)
2.2 koa-router module routing
npm install koa-router
const Koa = require('koa') const Router = require('koa-router') const app = new Koa() const router = new Router() app.use(router.routes()).use(router.allowedMethods()); //routes() returns to the router middleware, which schedules the routes that match the request. //allowedMethods() handles the business of enriching the header header of the response object when ctx.status is empty or 404 after the execution of all routing middleware. router.get('/',(ctx,next)=>{//A. get is a get request sent ctx.response.body = '<h1>home page</h1>' }) router.get('/my',(ctx,next)=>{ ctx.response.body = '<h1>Contact us</h1>' }) app.listen(3000)
2.3 Static Resources
If the website provides static resources (pictures, fonts, stylesheets, scripts...), it will be very troublesome to write routing for them one by one, and there is no need for the koa-static module to encapsulate this part of the request. See the following examples
npm install koa-staic
const Koa = require('koa'); const app = new Koa(); const path = require('path'); const serve = require('koa-static'); const main = serve(path.join(__dirname)); app.use(main); app.listen(3000);
Visit http://localhost:3000/data/index.html, you can see the contents of this file in the browser.
2.4 redirect jump
In some cases, the server needs to redirect access requests. For example, after a user logs in, redirect him to the page before he logs in. The ctx.response.redirect() method can emit a jump that directs the user to another route.
const Koa = require('koa'); const Router = require('koa-router'); const app = new Koa(); const router = new Router() app.use(router.routes()).use(router.allowedMethods()); router.get('/cdx',(ctx,next)=>{ ctx.response.redirect('/');//Send out a jump to direct the user to another route. }) router.get('/',(ctx,next)=>{ ctx.body = 'Hello World'; }) app.listen(3000);
Visit http://localhost:3000/cdx, browsers will guide users to root routing.
3. Middleware
3.1 Logger function
One of Koa's greatest features and most important design is middleware. To understand middleware, let's first look at the implementation of Logger.
./logger/koa-logger.js
module.exports = (ctx, next) => { console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`);//custom }
./logger.js
const Koa = require('koa') const koaLogger = require('./logger/koa-logger') const app = new Koa(); app.use(koaLogger) app.listen(3000)
Print results
3.2 Middleware Concept
In the middle of HTTP Request and HTTP Response, the function used to implement some intermediate function is called "middleware".
Basically, all of Koa's functions are implemented through middleware, and the main in the previous example is also middleware. Each middleware accepts two parameters by default. The first parameter is the Context object and the second parameter is the next function. As long as the next function is called, execution can be transferred to the next middleware.
Multiple middleware will form a stack structure, which will be executed in the order of "first in, last out".
- The outermost middleware executes first.
- Call the next function to give execution to the next middleware.
- ...
- The innermost middleware is finally executed.
- After execution, the execution right is returned to the upper middleware.
- ...
- After the outermost middleware regains execution rights, it executes the code behind the next function.
Example:
const Koa = require('koa'); const app = new Koa(); app.use((ctx, next)=>{ console.log('>> one'); next(); console.log('<< one'); }) app.use((ctx, next)=>{ console.log('>> two'); next(); console.log('<< two'); }) app.use((ctx, next)=>{ console.log('>> three'); next(); console.log('<< three'); }) app.listen(3000);
Output results:
If the next function is not called inside the middleware, the execution right will not be passed on.
3.4 Asynchronous Middleware
So far, all examples of middleware are synchronous and do not include asynchronous operations. If there are asynchronous operations (such as reading a database), the middleware must be written as an async function.
npm install fs.promised
const fs = require('fs.promised'); const Koa = require('koa'); const app = new Koa(); const main = async function (ctx, next) { ctx.response.type = 'html'; ctx.response.body = await fs.readFile('./data/index.html', 'utf8'); }; app.use(main); app.listen(3000);
In the above code, fs.readFile is an asynchronous operation that must be written as await fs.readFile(), and then the middleware must be written as an async function.
app.use(async(ctx, next)=>{ ctx.body = '1' //Delay 2 seconds to execute the next middleware, which is useless because it is an asynchronous function setTimeout(()=>{ next() },2000) ctx.body += '2' }) app.use(async(ctx, next)=>{ ctx.body += '3' next() ctx.body += '4' }) server.js Correct approach function delay(){ return new Promise((reslove,reject)=>{ setTimeout(()=>{ reslove() },1000) }) } app.use(async(ctx, next)=>{ ctx.body = '1' await next() ctx.body += '2' }) app.use(async(ctx, next)=>{ ctx.body += '3' await delay() await next() ctx.body += '4' })
Synthesis of 3.5 Middleware
koa-compose module can synthesize multiple middleware into one.
npm install koa-compose
const Koa = require('koa'); const compose = require('koa-compose'); const app = new Koa(); const logger = (ctx, next) => { console.log(`${Date.now()} ${ctx.request.method} ${ctx.request.url}`); next(); } const main = ctx => { ctx.response.body = 'Hello World'; }; const middlewares = compose([logger, main]);//Fusion Middleware app.use(middlewares);//Loading Middleware app.listen(3000);
Output: Print the log first, then display Hello World on the page
IV. Handling Errors
4.1 500 errors
If there is an error in the code, we need to return the error information to the user. The HTTP protocol stipulates that 500 status codes will be returned at this time. Koa provides the ctx.throw() method to throw errors, ctx.throw(500) is to throw 500 errors.
const Koa = require('koa'); const app = new Koa(); const main = ctx => { ctx.throw(500);//At this time, when you visit the home page, you will report a 500 error (internal server error) and the server will report an error. }; app.use(main); app.listen(3000);
4.2 404 error
Setting ctx.response.status to 404 is equivalent to ctx.throw(404), returning 404 errors.
const Koa = require('koa'); const app = new Koa(); const main = ctx => { ctx.response.status = 404;//The status code returned by response is 404 ctx.response.body = 'Page Not Found';//Let the page display the content, the server does not report errors }; app.use(main); app.listen(3000);
4.3 Middleware for Error Handling
To handle errors easily, try...catch is the best way to capture them. However, it's too cumbersome to write try...catch for every middleware. We can make the outermost middleware responsible for the error handling of all middleware.
const Koa = require('koa'); const app = new Koa(); const handler = async (ctx, next) => { try { await next();//Execute the next Middleware } catch (err) { //If main middleware is a problem, it will go here. ctx.response.status = err.statusCode || err.status || 500; ctx.response.body = { message: err.message//Return the error message to the page }; } }; const main = ctx => { ctx.throw(500);//If there is no problem, it will be executed normally. If there is a problem, it will go catach. }; app.use(handler); app.use(main); app.listen(3000);
4.4 Erors Event Monitoring
Once an error occurs during the run, Koa triggers an error event. Listening for this event can also handle errors.
const Koa = require('koa'); const app = new Koa(); const main = ctx => { ctx.throw(500); }; app.on('error', (err, ctx) => { //If you make a mistake, you'll go here. console.error('server error', err);//Er is the source of err or }); app.use(main); app.listen(3000);
4.5 Release error events
It should be noted that if the error is caught by try...catch, the error event will not be triggered. At this point, ctx.app.emit() must be called to manually release the error event in order for the listener function to take effect.
const Koa = require('koa'); const app = new Koa(); const handler = async (ctx, next) => { try { await next(); } catch (err) { ctx.response.status = err.statusCode || err.status || 500; ctx.response.type = 'html'; ctx.response.body = '<p>If you have any questions, please contact the administrator.</p>'; ctx.app.emit('error', err, ctx);//Release error events } }; const main = ctx => { ctx.throw(500); }; app.on('error', function (err) { //The listener function here will take effect only after the error event is released console.log('error', err.message); console.log(err); }); app.use(handler); app.use(main); app.listen(3000);
The main function of the code above throws an error and is captured by the handler function. The catch block uses ctx.app.emit() to manually release error events so that the listener function can listen.
5. Functions of Web App
5.1 cookie
ctx.cookies are used to read and write cookies.
const Koa = require('koa'); const app = new Koa(); const main = function(ctx) { //Reading cookie//does not return 0 const n = Number(ctx.cookies.get('view') || 0) + 1; ctx.cookies.set('view', n);//Set cookie ctx.response.body = n + ' views';//Display cookie } app.use(main); app.listen(3000);
5.2 form
Web applications can't do without processing forms. Essentially, a form is a key-value pair that the POST method sends to the server. The koa-body module can be used to extract key-value pairs from the data body of the POST request.
npm install koa-body
const Koa = require('koa'); const koaBody = require('koa-body'); const app = new Koa(); const main = async function (ctx) { const body = ctx.request.body; if (!body.name){ ctx.throw(400, '.name required') }; ctx.body = { name: body.name }; }; app.use(koaBody()); app.use(main); app.listen(3000);
The above code uses the POST method to send a key-value pair to the server, which will be parsed correctly. If the data sent is incorrect, an error message will be received.
5.3 File Upload
The koa-body module can also be used to process file uploads.
. / demo / file upload. js
const Koa = require('koa'); const koaBody = require('koa-body'); const Router = require('koa-router'); const fs = require('fs'); const path = require('path'); const router = new Router() const app = new Koa(); app.use(koaBody({ multipart: true,//Parse multi-part principals, default false formidable: { maxFileSize: 200 * 1024 * 1024 // Set maximum upload file size limit, default 2M } })); app.use(router.routes()).use(router.allowedMethods()); router.post('/uploadfile', (ctx, next) => { // Upload a single file const file = ctx.request.files.file; // Getting Uploaded Files // Creating Readable Stream const reader = fs.createReadStream(file.path); let filePath = path.join(__dirname, 'data/') + `/${file.name}`; // Creating Writable Stream const upStream = fs.createWriteStream(filePath); // Readable streams are written to writable streams through pipes reader.pipe(upStream); return ctx.body = "Upload success!"; }); app.listen(3000)
./demo/web/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <form action="http://127.0.0.1:3000/uploadfile" method="post" enctype="multipart/form-data"> <input type="file" name="file" id="file" value="" multiple="multiple" /> <input type="submit" value="Submission"/> </form> </body> </html>
fs file system module in nodejs can help you read and write files, but it will not help you create folders.
The source of this paper is http://www.ruanyifeng.com/blog/2017/08/koa.html.