内容简介:在网络请求中,请求往往分成两种类型,一种是静态资源,直接从服务器的文件存储中读取,一种是动态资源,一般需要先从数据库获取数据,然后经过一定的处理,最后返回给客户端。根据上面的思想,所以实现简单版的static,可以将static单独存在一个js文件按中,然后require进来,这样使用和koa一样:以ejs模板为例,假设要渲染的模板是:
- koa-session:让无状态的http拥有状态,基于cookie实现的后台保存信息的session
- koa-mysql:封装了需要用到的 SQL 语句
- koa-mysql-session:当不想让session存储到内存,而想让session存储到 mysql 数据库中时使用
- koa-router:后台会接受到各种请求的url,路由会根据不同的url来使用不同的处理逻辑。
- koa-view:请求html页面时,后台会用模板引擎渲染数据到模板上,然后返回给后台
- koa-static:请求img、js、css等文件时,不需要其他逻辑,只需要读取文件
- koa-better-body:post上传文件时,解析请求体
koa系列文章:
- koa框架会用也会写—(koa的实现)
- koa框架会用也会写—(koa-router)
- koa框架会用也会写—(koa-view、koa-static)
- koa框架会用也会写—(koa-bodyparser、koa-better-body)
静态资源和动态资源
在网络请求中,请求往往分成两种类型,一种是静态资源,直接从服务器的文件存储中读取,一种是动态资源,一般需要先从数据库获取数据,然后经过一定的处理,最后返回给客户端。
- koa-static:用来处理静态资源的访问,因为它不涉及其他的处理过程,只是单纯的读取文件,所以单独抽离出来。
- koa-view是用来将数据和模板结合渲染html页面时采用的,渲染模板的逻辑都市一样的,所以也单独抽离出来。
koa-static
- 判断请求的文件是否存在,如果存在读取文件返回
- 如果请求的文件不存在,则默认查看当前文件下是否有index.html,如果存在返回当前文件下的index.html
根据上面的思想,所以实现简单版的static,可以将static单独存在一个js文件按中,然后require进来,这样使用和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) } else { //如果不是文件,则判断是否存在index.html 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
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%>将其变成${xx}
- 匹配<%xxxx%>将xxxx中的内容拼接起来变成一个函数字符串
- 然后通过new Function函数字符串生成一个函数执行数据就会返回渲染后的字符串
//简化渲染模板便于理解,去掉其他标签,真实渲染时,这些标签时存在的 <body> <%arr.forEach(a=>{%> <li><%=a%></li> <%})%> </body> 复制代码
ejs中的render函数,简化版本:
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 //} 复制代码
koa-view的原理
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函数,读取文件,然后渲染 ctx.render = async (filename,obj) => { let realPath = path.join(p,filename); let { promisify} = require('util'); let fs = require('fs'); let read = promisify(fs.readFile); //promise化 let r = await read(realPath,'utf8'); ctx.body = render(r, obj); } return next(); } } module.exports = views; 复制代码
渲染页面的逻辑:
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), { map: { html: 'ejs' } })); router.get('/',async (ctx,next)=> { await ctx.render('template.html',{arr:[1,2,3]}) }) app.listen(3000); 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 基于Google MVVM框架的baseMVVM框架
- Spring 框架是怎么出生的(二):重构提炼出框架
- Spring 框架是怎么出生的(二):重构提炼出框架
- Genesis框架从入门到精通(7): 框架的过滤器
- 如何打造自己的POC框架-Pocsuite3-框架篇
- 如何打造自己的PoC框架-Pocsuite3-框架篇
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
笨办法学Python 3
[美]泽德 A. 肖 / 王巍巍 / 人民邮电出版社 / 2018-6-1 / CNY 59.00
本书是一本Python入门书,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用。这本书以习题的方式引导读者一步一步学习编程,从简单的打印一直讲到完整项目的实现,让初学者从基础的编程技术入手,最终体验到软件开发的基本过程。本书是基于Python 3.6版本编写的。 本书结构非常简单,除“准备工作”之外,还包括52个习题,其中26个覆盖了输入/输出、变量和函数3个主题,另外26个......一起来看看 《笨办法学Python 3》 这本书的介绍吧!