一文彻底搞懂koa2和ejs

2023-08-21  本文已影响0人  硅谷干货

一、安装

开发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(从外到内,再从内到外)

如图:

[图片上传失败...(image-559dff-1692700854499)]

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文件

<h1>我是公共header</h1>
然后通过 <%- include('public/header.ejs') -%>引入

5.4 绑定数据

nodejs部分

router.get('/', async (ctx) => {
    let content = '<h3>我是数据</h3>'
    await ctx.render('index',{
        content:content
    })
})

ejs部分

<%=content%>

可是这样输出的是 <h3>我是数据</h3>,不能解析<h3>标签

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

<%-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引入的时候,不要写外部的文件夹

比如:<link rel="stylesheet" href="../static/css/style.css"> 这样写是不行的

<link rel="stylesheet" href="css/style.css"> 这样写就可以了

同样,图片引入的时候也不用写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的参数

[图片上传失败...(image-fd84b1-1692700854499)]

· 实现多个页面之间的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;
})
上一篇下一篇

猜你喜欢

热点阅读