Middleware commonly used in Koa:

  • Koa-session: a session that allows stateless HTTP to have state, and a cookie based implementation to store information in the background
  • Koa-mysql: encapsulates SQL statements that need to be used
  • Koa-mysql-session: used when you do not want the session to be stored in memory but want the session to be stored in the mysql database
  • Koa-router: The background receives the REQUESTED URL, and the route uses different processing logic based on the URL.
  • Koa-view: When an HTML page is requested, the background uses the template engine to render the data to the template and then returns it to the background
  • Koa-static: To request img, JS, and CSS files, no other logic is required
  • Koa-better-body: Parses the request body when the post uploads the file

Koa series of articles:

  • The KOA framework will use and write — (koA implementation)
  • The KOA framework will use and write — (koa-router)
  • The KOA framework will use and write — (koa-view, koa-static)
  • – KoA frameworks will be used and written — (koA-bodyParser, KoA-better-Body)

The encType attribute of the form tag

  • Application/X-www-form-urlencoded: Encode all characters before sending (default not set)
  • Multipart /form-data: No character encoding. This value must be used when using forms that contain file upload controls.
  • Text /plain: Spaces are converted to “+” plus signs, but no special character encoding.

The above text may not seem intuitive, so send your own request to view it:

// the foreground page login. HTML <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, <meta http-equiv=" x-UA-compatible "content=" IE =edge"> <title>Document</title>  href="/bootstrap/dist/css/bootstrap.css"> </head> <body> <form action="/fileupload" enctype="text/plain" method="POST"> <div class="form-group"> <label for="username" class="control-label"> </label> <input type="text" class="form-control" id="username" name="username"> </div> <div class="form-group"> <label for="password" Class ="control-label"> password </label> <input type="text" class="form-control" id="password" name="password"> </div> <div Class ="form-group"> <label for="avatar" class="control-label"> </label> <input type="file" multiple class="form-control" id="avatar" name="avatar"> </div> <div class="form-group"> <button type="submit" class="btn BTN - danger "> login < / button > < / div > < / form > < / body > < / HTML >Copy the code
// const Koa = require(' Koa '); const path = require('path'); const Router = require('koa-router'); const static = require('koa-static'); const session = require('koa-session'); let app = new Koa(); let router = new Router(); app.keys = ['jx','kbz']; app.use(session({ maxAge:5*1000, }, app)); app.use(static(path.resolve(__dirname))); app.use(static(path.resolve(__dirname,'node_modules'))); Router.post ('/login', Async (CTX,next)=>{// Obtain the user account and password ctx.session.user = ctx.request.body ctx.body = ctx.session.user; }); router.get('/home',async (ctx,next)=>{ if (ctx.session.user){ ctx.body = { status:1, username: ctx.session.user.username } }else{ ctx.body = { status: 0, username: null } } }) router.post('/fileupload',async(ctx,next)=>{ console.log('upload') }) app.use(router.routes()); app.listen(3000);Copy the code

HTML form form encType attribute changed to Text /plain, application/ X-www-form-urlencoded, multipart/form-data:

  • Text /plain request body: Spaces are converted to “+” plus signs, but no special character encoding

  • Application/X-www-form-urlencoded Request body: Encode all characters before sending (default not set)

  • Multipart /form-data: No character encoding. This value must be used when using forms that contain file upload controls.

As can be seen from the picture above:

  1. Normal form submission uses Application/X-www-form-urlencoded with more strings than text/plain
  2. Application/X-www-form-urlencoded, text/plain will submit file names only, the content will not be seen in the request body. But multipart/form-data does

The difference between KoA-BodyParser and KoA-better-Body

  • Koa-bodyparser does not handle file uploads, whereas KoA-better-Body does
  • Koa-bodyparser mounts the request body on ctx.request.body, while koA-better-Body mounts the request body on ctx.request.fields

The principle of koa – bodyparser

// Use buffer to cache data. Async and await function bodyParser() {return async (CTX, next) => {await new Promise((resolve, resolve, reject) => { let arr = []; ctx.req.on('data', function (data) { arr.push(data); }); ctx.req.on('end', function () { let r = Buffer.concat(arr).toString(); ctx.request.body = r; resolve(); })}); await next(); }}Copy the code

The principle of koa – better – body

It can be seen from the above two figures that there is a boundary attribute in the contentType of the request header, and the data in the request body are separated by the value of this boundary attribute. The content inside can be removed by segmentation. Since the file is binary, we need to split the buffer, but the prototype buffer does not have this method, so we extend the split method:

Buffer.prototype.split = function (sep) {let len = buffer.from (sep).length; let pos = 0; let index = 0; let arr = []; // Check whether there is still a boundary behind the pos bit. // Cut the content of the boundary into the array. = (index = this.indexOf(sep,pos))) { arr.push(this.slice(pos,index)); Pos = len + index; } // Insert the last contents of the boundary into the array arr.push(this.slice(pos)); return arr; } let buffer = buffer.form ('b**b**b**b--').split('b') console.log(buffer); //[<Buffer >,<Buffer 2a 2a>,<Buffer 2a 2a>,<Buffer 2a 2a>,<Buffer 2d 2d>]Copy the code

After intercepting the desired content, further processing can be done:

  • The content contains the content of filename’s fetch except for the green part
  • Ctx.request.fields.xx = xx Does not contain the composition of filename
function betterBody({uploadDir}) { return async (ctx,next)=>{ await new Promise((resolve,reject)=>{ let arr = []; ctx.req.on('data', function (data) { arr.push(data); }); ctx.req.on('end', function () { if (ctx.get('content-type').includes('multipart')) { let r = Buffer.concat(arr); Let boundary =' --' + ctx.get('content-type').split('=')[1]; //[<Buffer 2a 2a>,<Buffer 2a 2a>,<Buffer 2a 2a>] let lines = r.split(boundary).slice(1, -1); let fileds = {}; // Handle lines with and without filename. ForEach ((line) => {let [head, content] = line.split('\r\n\r\n'); head = head.toString(); If (head. Includes ('filename')) {if (head. Includes ('filename')) {if (head. Includes ('filename')) {if (head 4, 2); let uuid = require('uuid/v4'); let fs = require('fs'); let p = uuid(); fs.writeFileSync(path.resolve(__dirname, uploadDir, p), content); fileds['path'] = p; } else {// Not a file, mount parameters for example: username let key = head.match(/name="([\s]*)"/im)[1]; \r\n let value = content.toString().slice(0, -2); fileds[key] = value; }; }) ctx.request.fields = fileds; resolve(); } }) }) await next() } }Copy the code

conclusion

Koa framework will use will also write the content of the series is basically introduced, welcome to correct!