读完这篇文章彻底搞懂koa和ejs

koa教程

一、安装

开发koa2之前,要求nodejs版本要高于v7.6。因为nodejs7.6版本开始完全支持async/await,所以才能完全支持koa2

安装语法 : npm install koa --save-dev
使用之前,先npm init 初始化

二、简单使用

var koa= require( ‘koa’);
var app= new koa();
//中间件,express中的req,res参数变成了ctx
app.use(async(ctx)=>{
    
        
   ctx.body=”你好koa2.x”
})
app.listen(3000);

三、koa路由

3.1 基本实现
· koa中的路由跟express有所不同,我们需要安装对应的koa-router路由模块来实现

npm install koa-router --save-dev
引入:

var koa =require('koa');
var router=require('koa-router')();
var app=new koa();
//ctx 上下文context, 包含了request和response等信息
router.get('/', async (ctx) => {
    
    
   ctx.body=’首页’//相当于res.end( )
}).get('/news', async (ctx) => {
    
     //可以连续使用,也可以分开用
  ctx.body='这是一个新闻页面'
})
app.use(router.routes())//启动路由
app.use(router.allowedMethods()) 
//作用:这是官方文档的推荐用法,
//我们可以看到router.allowedMethods()用在了路由匹配router.routes()之后,
//所以在当所有路由中间件最后调用,此时根据ctx.status设置响应头
app.listen(3000)

3.2 get传值
如何获取参数?

方式一:(推荐)
ctx.query //打印{aid: ‘123’} 获取的是对象(用的最多的方式)
ctx.querystring // aid=123&name=zhangsan 获取的是一个字符串

方式二:我们可以从ctx里面的request里面获取get传值
ctx.request.requery // {aid: ‘123’}
ctx.quest.querystring // aid=123&name=zhangsan

3.3 动态路由

router.get('/newscontent/:aid', async (ctx) => {
    
    
   console.log(ctx.params) // { aid : ‘123’}
   ctx.body = '新闻详情'
})

动态路由可以传入多个值

router.get('/newscontent/:aid/:cid', async (ctx) => {
    
    
   console.log(ctx.params) //{aid:’123’ , cid: ‘456’}
   ctx.body = '新闻详情'
})

四、koa中间件

4.1 中间件使用
中间件的功能:
· 执行任何代码
· 修改请求和响应对象
· 终结请求–响应循环
· 调用堆栈中的下一个中间件

如果get、post回调函数中没有next参数,name就匹配上第一个路由,就不会往下匹配了,如果想往下匹配,那么就需要写next()

4.2 应用级中间件
· 定义:就是在匹配所有路由之前进行操作某种需求

const Koa = require('koa');
const router = require('koa-router')();
const app = new Koa();
// 中间件,匹配任何路由,也就是在匹配任何路由之前调用它
app.use(async(ctx,next)=>{
    
     
    ctx.body="中间件"
    console.log(new Date())
    await next() // 当前路由匹配完成以后继续向下匹配,不写就不会向下匹配
})
router.get('/', async (ctx) => {
    
    
    ctx.body = '首页'
})
router.get('/news', async (ctx) => {
    
    
    ctx.body = '新闻'
})
app.use(router.routes()); //启动路由
app.use(router.allowedMethods())
app.listen(3000)

4.3 路由中间件
· 定义: 匹配特定路由前进行某种操作

router.get('/news', async (ctx,next) => {
    
    //匹配到news路由后继续向下匹配路由
  console.log(“新闻中间件”)
  await next()
})
router.get('/news', async (ctx) => {
    
    
    ctx.body = '新闻'
})

4.4 错误处理中间件
· express的中间件和路由有前后顺序,而koa没有顺序,即使放在路由最后面,也先执行中间件

例子:404页面

app.use(async(ctx,next)=>{
    
     
  	console.log('这是一个中间件01')
  	await next() 
	if(ctx.status==404){
    
    
	  ctx.status=404;
	  ctx.body="这是一个404页面"
	}else{
    
    
	  console.log('正常')
	}
})
router.get('/', async (ctx) => {
    
    
    ctx.body = '首页'
})

打印结果:这是一个中间件01 -> 首页 -> 正常

执行顺序,先打印:这是一个中间件01,然后执行next()下面的路由,当执行完路由返回结果后,再回到app.use中间件,执行if判断

· 这时候我们就要说一下koa的执行模式

app.use(async(ctx,next)=>{
    
     
    console.log('中间件01')
    await next() 
    console.log('1')
})
app.use(async(ctx,next)=>{
    
     
    console.log('中间件02')
    await next() 
    console.log('2')
})
app.use(async(ctx,next)=>{
    
     
    console.log('中间件03')
    await next() 
    console.log('3')
})
 
 
router.get('/', async (ctx) => {
    
    
    ctx.body = '首页'
})
router.get('/news', async (ctx) => {
    
    
    console.log('匹配到新闻页面')
    ctx.body = '新闻'
})

执行结果:

中间件01 ->中间件02 ->中间件03->匹配到新闻页面-> 3 -> 2 -> 1

koa就像洋葱一样,先执行request,然后再执行response(从外到内,再从内到外)

如图:
在这里插入图片描述

4.5 第三方中间件

五、 ejs模板引擎

5.1 安装 koa-views ejs
· npm install koa-views --save
· npm install ejs --save
5.2 使用

const Koa = require('koa');
const views =require('koa-views')
const router = require('koa-router')();
const app = new Koa();
// app.use(views(__dirname + '/views', {map: {html: 'ejs'}})) 这种方式文件名得写index.html
app.use(views(__dirname+'/views', {
    
     extension: 'ejs' })) 这种写index.ejs
router.get('/', async (ctx) => {
    
    
  let title=”hello world
  let arr=[‘刚刚’,‘他娃儿噶’,‘大幅度’]
  await ctx.render('index',{
    
      //别忘了加 await
     title:title,
     arr:arr
  })
})

html部分

<h1>这是一个ejs的模板引擎</h1>
<h2><%= title %></h2>
<ul>
   <% for(var i=0; i<arr.length; i++){
     
      %>
     <li><%= arr[i] %></li>
    <% }%>
</ul>

5.3 可以引入公共header 和footer
新建一个header.ejs文件

我是公共header

然后通过 <%- include('public/header.ejs') -%>引入 5.4 绑定数据 nodejs部分
router.get('/', async (ctx) => {
    
    
    let content = '<h3>我是数据</h3>'
    await ctx.render('index',{
    
    
        content:content
    })
})

ejs部分

<%=content%>
可是这样输出的是

我是数据

,不能解析

标签

这时候我们需要用<%- %>

<%-content%>这样就可以了
5.5 条件判断

router.get('/', async (ctx) => {
    
    
   let number=123
    await ctx.render('index',{
    
    
       number:number
    })
})

ejs部分

<% if(number>20){%>
    <p>大于20</p>
    <%} else {%>
    <p>小于20</p>
<%}%>

5.6 如何配置公共数据
· 如果所有的页面都需要同一个数据的时候,该怎么办呢?

当然你也可以一个页面写一个,但是如果有几十个上百个页面那就太麻烦了,这时候我们就可以在中间件的ctx.state中去定义

例子:比如每个页面都需要userInfo数据

我们可以这样做

nodejs部分

app.use(anync (ctx,next) =>{
    
    
  	ctx.state.userInfo=”我是公共数据”
 	await next()
})

ejs调用

<%=userInfo%>

六、 koa post提交数据

6.1 nodejs原生实现接收表单请求数据
ejs部分

<form action="/doAdd" method="post">
   <label for="">用户名:</label>
   <input type="text" name="username">
   <br>
   <label for="">密码:</label>
   <input type="password" name="password">
   <br>
   <button type="submit">确定</button>
</form>

nodejs部分

const Koa = require('koa');
const views =require('koa-views')
const router = require('koa-router')();
const common =require('./module/common.js')
const app = new Koa();
 
app.use(views(__dirname+'/views', {
    
     extension: 'ejs' }))
router.get('/', async (ctx) => {
    
    
    await ctx.render('index.ejs')
})
 
router.post('/doAdd', async (ctx) => {
    
    
    var data= await common.getPostData(ctx)
    console.log(data)
    ctx.body=data;
 
})
 
app.use(router.routes()); //启动路由
app.use(router.allowedMethods())
app.listen(3000)

我们新建了一个module文件夹,在里面新建了一个common.js

通过node原生代码实现接收客户端请求的数据

在common.js中封装了一个函数getPostData

代码如下

exports.getPostData=function(ctx){
    
    
  return new Promise(function(resolve,reject){
    
    
    try{
    
    
      var str='';
      ctx.req.on('data',function(chunk){
    
    
         str+=chunk;
       })
      ctx.req.on('end',function(chunk){
    
    
         resolve(str)
      })
    }catch(err){
    
    
      reject(err)
    }
 })
}

6.2 koa-bodyparser获取表单提交的数据
①先安装

npm install koa-bodyparser --save
② 引入

const bodyParser =require(‘koa-bodyparser’)
③配置koa-bodyparser中间件

app.use(bodyParser())
④ 获取表单提交的数据

ctx.request.body
代码如下

router.post(‘/doAdd’, async (ctx) => {
var data = ctx.request.body
ctx.body=data;
})

七、 koa-static 静态资源中间件

为什么要用它?

像css文件,如果只用link引入的话是无效的,这时候就用到了koa-static来处理静态资源

① 安装

npm install koa-static --save
② 引入

const static = require(‘koa-static’)
③ 配置,可以配置多个

app.use(static(__dirname+‘/static’))
首先去static寻找,如果找到了返回对应的文件,找不到就next()

注意:link引入的时候,不要写外部的文件夹

比如: 这样写是不行的

这样写就可以了

同样,图片引入的时候也不用写static

八、 art-template模板引擎(看官网)

art-template 是一个简约、超快的模板引擎。

它采用作用域预声明的技术来优化模板渲染速度,从而获得接近 JavaScript 极限的运行性能,并且同时支持 NodeJS 和浏览器。

用两种写法:①跟ejs类似 ② 跟angular类似

render(app, {
root: path.join(__dirname, ‘view’), //视图
extname: ‘.art’, //后缀名
debug: process.env.NODE_ENV !== ‘production’ //是否开启调试
});

九、 koa中cookie的使用

9.1 cookie 简介

· cookie是存储于访问者的计算机中的变量

· http协议是无状态的

· cookie的作用

① 保存用户信息

② 浏览器历史记录

③ 猜你喜欢的功能

④ 10天免登陆

⑤ 多个页面之间的数据传递

⑥ cookie实现购物车功能

9.2 koa中设置cookie的值
ctx.cookies.set(name,value,[options])
通过options设置cookie 中name 的value的配置

cookie的参数

· 实现多个页面之间的cookie共享

router.get('/', async (ctx) => {
    
    
  ctx.cookies.set('userinfo','zhangsan',{
    
    
     maxAge:60*1000*60//多长时间以后过期
     path:/news’,//特定路径才能访问
    domain:.baidu.com’,
// 表示 a. baidu.com  b.baidu.com 可以共享cookie的数据, 
//正常情况下不要设置,默认就是当前域下面的所有页面都可以访问
      httpOnly:true , 
//true表示这个cookie只有服务器端可以访问(在页面中通过js访问不到),
//false表示服务端和都可以访问
    })
    await ctx.render('index.ejs')
})
router.get('/news', async (ctx) => {
    
    
    var cookdata = ctx.cookies.get('userinfo')
    ctx.body = cookdata;
})

9.3 koa中的cookie的bug
· 如果设置cookie的值为中文时会报错

router.get('/', async (ctx) => {
    
    
  ctx.cookies.set('userinfo',‘张三’,{
    
     //会报错
     maxAge:60*1000*60
  }}

解决方法:

运用buffer将汉字转换成base64 字符 ,最后再将base64还原会汉字

router.get('/', async (ctx) => {
    
    
  var userinfo = new Buffer(‘张三’).toString(‘base64’)
  ctx.cookies.set('userinfo',userinfo ,{
    
    
    maxAge:60*1000*60                  
 })
  await ctx.render('index.ejs')
})
router.get('/news', async (ctx) => {
    
    
var cookdata = ctx.cookies.get('userinfo')
var userinfo = new Buffer(cookdata ,’base64’).toString()
    ctx.body = userinfo;
})

猜你喜欢

转载自blog.csdn.net/weixin_36557877/article/details/129316088