Будет использоваться и написана структура koa — (koa-view, koa-static)

koa

Промежуточное ПО, обычно используемое в Koa:

  • koa-session: позволить HTTP без сохранения состояния иметь состояние, а сеанс, основанный на cookie, для сохранения информации в фоновом режиме.
  • koa-mysql: инкапсулирует операторы SQL, которые необходимо использовать.
  • koa-mysql-session: когда вы не хотите, чтобы сеанс хранился в памяти, и когда вы хотите сохранить сеанс, используйте базу данных mysql
  • koa-router: фон будет получать URL-адреса различных запросов, а маршрутизация будет использовать различную логику обработки в соответствии с разными URL-адресами.
  • koa-view: при запросе html-страницы фон будет использовать механизм шаблонов для рендеринга данных в шаблон, а затем вернуть их в фон
  • koa-static: При запросе img, js, css и других файлов никакой другой логики не требуется, нужно только прочитать файл
  • koa-better-body: когда сообщение загружает файл, анализировать тело запроса

Серия статей КОА:

Статические и динамические ресурсы

В сетевых запросах запросы часто делятся на два типа, один — это статические ресурсы, которые считываются непосредственно из файлового хранилища сервера, а другой — это динамические ресурсы, которые, как правило, сначала должны получить данные из базы данных, а затем пройти через определенные обработка и, наконец, возврат клиенту.

  • koa-static: используется для обработки доступа к статическим ресурсам, поскольку не задействует другие процессы обработки, а просто читает файлы, поэтому извлекается отдельно.
  • KOA-View используется для использования данных и шаблонов для рендеринга HTML-страницы, логика шаблона рендеринга такая же, поэтому он также отделен отдельно.

koa-static

  • Определить, существует ли запрошенный файл, если он существует, прочитать файл и вернуться
  • Если запрошенный файл не существует, по умолчанию возвращается index.html текущего файла.

В соответствии с приведенной выше идеей, чтобы получить простую версию static, вы можете сохранить static в файле js отдельно, а затем потребовать его, что аналогично koa:

const Koa = require('koa');
const path = require('path');
const Router = require('koa-router');
const fs = require('fs');
const {promisify} = require('util');    //将函数promise化
const stat = promisify(fs.stat);    	//用来获取文件的信息
const mime = require('mime');   	//mime类型获取插件
let app = new Koa();
let router = new Router();
function static(dir) {
    return async (ctx,next)=>{
        let pathname = ctx.path;
        //获取请求文件的绝对路径
        let realPath = path.join(dir,pathname); 
    try{
        let statObj = await stat(realPath);
        //如果是文件则读取文件,并且设置好相应的响应头
        if (statObj.isFile()) {
            ctx.set('Content-Type', mime.getType(realPath)+";charset=utf-8");
            ctx.body = fs.createReadStream(realPath)
        //如果不是文件,则判断是否存在index.html
      } else {
            let filename = path.join(realPath, 'index.html')
            await stat(filename)
            ctx.set('Content-Type', "text/html;charset=utf-8");
            ctx.body = fs.createReadStream(filename);
      }
    }catch(e){
    	//出错直接跳过这个中间件
        await next();   
    }
  }
}
app.use(static(path.resolve(__dirname, 'public')));
app.use(router.routes());
app.listen(3000);

koa-view

использование коа-вида

Взяв в качестве примера шаблон ejs, предположим, что отрисовываемый шаблон:

//template.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>
  <%arr.forEach(a=>{%>
    <li><%=a%></li>
  <%})%>
</body>
</html>

Логика отрисовки страницы:

const Koa = require('koa');
const path = require('path');
const Router = require('koa-router')
const views = require('koa-views');
let app = new Koa();
let router = new Router();
app.use(views(path.resolve(__dirname), {
  //不设置的话,模板文件要使用.ejs后缀而不是.htmls后缀
  map: { html: 'ejs' }
}));
router.get('/',async (ctx,next)=> {
 await ctx.render('template.html',{arr:[1,2,3]})
})
app.listen(3000);

Принцип рендеринга EJS

В koa будет установлен метод рендеринга шаблона.Как правило, для рендеринга страницы будет использоваться шаблонизатор ejs:

  • Соответствие <%> превращает его в ${xx}
  • Сопоставьте <%xxxx%>, чтобы объединить содержимое xxxx в строку функции.
  • Затем сгенерируйте данные выполнения функции через новую строку функции Function и верните обработанную строку.
//简化渲染模板便于理解,去掉其他标签,真实渲染时,这些标签是存在的
<body>
  <%arr.forEach(a=>{%>
    <li><%=a%></li>
  <%})%>
</body>

Функция рендеринга в ejs, упрощенная версия:

function render(r, obj) {
        let head = `let str=''\r\n`;
        
        //with可以将变量的上下文指向为obj,所以a => obj.a
        head += 'with(b){\r\n'
        let content = 'str+=`'
        
        //先将匹配<%=xx%>将其变成${xx}
        r = r.replace(/<%=([\s\S]*?)%>/g, function () {
            return '${' + arguments[1] + '}'
        });
        
        //匹配<%xxxx%>将xxxx中的内容拼接起来变成一个函数主要逻辑
        content += r.replace(/<%([\s\S]*?)%>/g, function () {
            return '`\r\n' + arguments[1] + "\r\n str+=`"
        });
        let tail = "`\r\n} \r\n return str";
        let fnStr = head + content + tail;
        let fn = new Function('b', fnStr)
        return fn(obj);
}

/*******************************************************************/

fn= function(b){
  let str='';
  with(b){
      str+='<body>';
      b.arr.forEach(a=>{str += '<li>${a}</li>'});
      str += '</body>';
  }
  return str
}  

Принцип коа-вида

let { promisify} = require('util');
let fs = require('fs');
let read = promisify(fs.readFile);  //promise化

function views(p,opts) {
  return async(ctx,next)=>{
    function render(r, obj) {
        let head = `let str=''\r\n`;
        head += 'with(b){\r\n'
        let content = 'str+=`'
        r = r.replace(/<%=([\s\S]*?)%>/g, function () {
            return '${' + arguments[1] + '}'
        });
        content += r.replace(/<%([\s\S]*?)%>/g, function () {
            return '`\r\n' + arguments[1] + "\r\n str+=`"
        });
        let tail = "`\r\n} \r\n return str";
        let fnStr = head + content + tail;
        let fn = new Function('b', fnStr)
        return fn(obj);
    } 
    //在ctx上挂在render函数,读取文件模版,然后使用render函数渲染
    ctx.render = async (filename,obj) => {
        let realPath = path.join(p,filename);
        let r = await read(realPath,'utf8');
        ctx.body = render(r, obj);
    }
    return next();
  }
}
module.exports = views;

Эпилог

В основном представлены принципы koa-view и koa-static middleware, а о других промежуточных слоях kao мы узнаем позже: