egg入门笔记

简介

Egg.js 为企业级框架和应用而生。基于Koa开发,性能优异。
奉行『约定优于配置』,按照一套统一的约定进行应用开发

egg中文官网上面非常详细,有koa2基础的话,上手很快

环境搭建

环境要求:

  • 要求nodejs版本必须大于8.0
  • 建议选择LTS版本
  • 全局安装egg-initnpm i egg-init -g

  • 创建项目(比如叫eggdemo)

egg-init eggdemo --type=simple cd eggdemo npm i
  • 运行项目:npm run dev
  • 使用浏览器打开http://localhost:7001

备注

  • vscode可以安装插件eggjs

目录结构

egg-project
├── package.json
├── app.js (可选)
├── agent.js (可选)
├── app
|   ├── router.js
│   ├── controller
│   |   └── home.js
│   ├── service (可选)
│   |   └── user.js
│   ├── middleware (可选)
│   |   └── response_time.js
│   ├── schedule (可选)
│   |   └── my_task.js
│   ├── public (可选)
│   |   └── reset.css
│   ├── view (可选)
│   |   └── home.tpl
│   └── extend (可选)
│       ├── helper.js (可选)
│       ├── request.js (可选)
│       ├── response.js (可选)
│       ├── context.js (可选)
│       ├── application.js (可选)
│       └── agent.js (可选)
├── config
|   ├── plugin.js
|   ├── config.default.js
│   ├── config.prod.js
|   ├── config.test.js (可选)
|   ├── config.local.js (可选)
|   └── config.unittest.js (可选)
└── test
    ├── middleware
    |   └── response_time.test.js
    └── controller
        └── home.test.js
  • app/router.js:用于配置URL路由规则
  • app/controller/**:用于解析用户的输入,处理后返回相应的结果
  • app/service/**:用于编写业务逻辑层,可选,建议使用
  • app/middleware/**:用于编写中间件,可选
  • app/public/**:用于放置静态资源,可选
  • app/extend/**:用于框架的扩展,可选
  • app/schedule/**:用于定时任务,可选
  • app/view/**:用于放置模板文件,可选
  • app/model/**:用于放置领域模型,可选
  • config/config.{env}.js:用于编写配置文件
  • config/plugin.js:用于配置需要加载的插件
  • test/**:用于单元测试
  • app.js:和agent.js用于自定义启动时的初始化工作,可选

路由-router.js

路由配置文件:app/router.js

'use strict'; /** * @param {Egg.Application} app - egg application */ module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.get('/logout', controller.home.loginOut); router.get('/news', controller.news.index); router.get('/news/detail/:id', controller.news.detail); router.get('/form1', controller.home.form1); router.get('/form2', controller.home.form2); router.post('/add', controller.home.add); router.get('/shop', controller.shop.index); };

更多路由配置参考

控制器-controller

有下面几个属性挂在this

  • this.ctx: 当前请求的上下文Context对象的实例,通过它我们可以拿到框架封装好的处理当前请求的各种便捷属性和方法。
  • this.app: 当前应用Application对象的实例,通过它我们可以拿到框架提供的全局对象和方法。
  • this.service:应用定义的Service,通过它我们可以访问到抽象出的业务层,等价于this.ctx.service
  • this.config:应用运行时的配置项。
  • this.loggerlogger对象,上面有四个方法(debuginfowarnerror),分别代表打印四个不同级别的日志
  • 获取query参数:/news?a=123&b=kkk
'use strict'; // app/controller/news.js const Controller = require('egg').Controller; class NewsController extends Controller { async index() { const { ctx } = this; const query = ctx.query console.log(query) // { a: 123, b: 'kkk' } ctx.body = 'news 页面'; } } module.exports = NewsController;
  • 获取动态路由中的params参数:/news/detail/123
'use strict'; // app/controller/news.js const Controller = require('egg').Controller; class NewsController extends Controller { async detail() { const { ctx } = this; const id = ctx.params.id console.log(id) // 123 ctx.body = 'news detail 页面'; } } module.exports = NewsController;

更多控制器信息参考

模板-view

比如使用egg-view-ejs模板引擎

  • 安装egg-view-ejs
npm i egg-view-ejs --save
  • 修改config/plugin.js文件
// ... module.exports = { // ... ejs: { enable: true, package: 'egg-view-ejs' } }
  • 修改config/config.default.js文件
// ... module.exports = appInfo => { // ... // 配置 ejs 模板引擎 config.view = { mapping: { '.html': 'ejs' } } // ... }
  • app/目录下新建view/目录

  • app/view/目录下新建home.html文件(以此为示例,这个就是首页的模板文件。文件名随意,会在controller中调用对应的文件名)

  • 修改app/controller/home.js文件

'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; await ctx.render('home') // 注意这里前面有个 await } }

静态资源-public

  • app/目录下新建public/目录

  • 静态资源放在此目录下即可(比如:有个图片app/public/images/1.jpg

  • 在模板中使用静态资源

<img src="/public/images/1.jpg" alt="">

配置-config

比如设置接口地址

  • 修改config/config.default.js文件(这个是默认配置文件,如果配置多环境,修改对应的config.xxx.js文件即可)
// ... module.exports = appInfo => { // ... // add your user config here const userConfig = { // myAppName: 'egg', // 配置公共API api: 'http://www.xxx.com/' }; return { ...config, ...userConfig, }; }
  • 修改app/controller/home.js。在controller中读取配置
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; console.log(config.api); await ctx.render('home') } }

更多配置信息参考:

数据模型-service

Service就是在复杂业务场景下用于做业务逻辑封装的一个抽象层

抽象的好处:

  • 保持Controller中的逻辑更加简洁。
  • 保持业务逻辑的独立性,抽象出来的Service可以被多个Controller重复调用。
  • 将逻辑和展现分离,更容易编写测试用例。

服务的命名规则

  • Service文件必须放在app/service/目录,可以支持多级目录,访问的时候可以通过目录名级联访问。
  • app/service/biz/user.js => ctx.service.biz.user (建议)****
  • app/service/sync_user.js => ctx.service.syncUser
  • app/service/HackerNews.js => ctx.service.hackerNews
  • app/目录下新建service/目录

  • app/service/目录下新建user.js文件

'use strict'; const Service = require('egg').Service; class UserService extends Service { async getUserInfo() { return { name: '张三', age: 20 } } } module.exports = UserService;
  • app/service/目录下新建news.js文件
'use strict'; const Service = require('egg').Service; class NewsService extends Service { async getNewsList() { const { config, service } = this // 获取config的数据 console.log(config.api); // 获取新闻数据 var list = ['11111','2222','333333333']; // 调用user服务的数据 var user = await service.user.getUserInfo(); console.log(user); return list; } } module.exports = NewsService;
  • app/controller/目录下添加news.js。使用service数据
'use strict'; const Controller = require('egg').Controller; class NewsController extends Controller { async index() { const { ctx, service } = this; var msg = 'ejs'; var list = await service.news.getNewsList(); await ctx.render('news/index',{ mag: msg, list }); } } module.exports = NewsController;
  • app/view/目录下添加目录news/

  • app/view/news/目录下添加模板文件index.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> <link rel="stylesheet" href="/public/css/basic.css"> </head> <body> <h2>这是一个新闻--<%=mag%></h2> <ul> <%for(var i=0;i<list.length;i++){%> <li><%=list[i]%></li> <%}%> </ul> <img src="/public/images/1.jpg" alt=""> </body> </html>

更多Service信息参考

HttpClient-curl

此框架基于urllib内置实现了一个HttpClient,应用可以非常便捷地完成任何HTTP请求。

框架在应用初始化的时候,会自动将HttpClient初始化到app.httpclient
同时增加了一个app.curl(url, options)方法,它等价于app.httpclient.request(url, options)

  • 修改config/config.default.js文件,增加配置api: 'http://www.phonegap100.com/'

  • 添加app/service/news.js文件

'use strict'; const Service = require('egg').Service; class NewsService extends Service { async getNewsList() { const { ctx, config } = this // 通过抓取接口返回数据 // curl的方法可以获取远程的数据 var api = config.api + 'appapi.php?a=getPortalList&catid=20&page=1' var response = await ctx.curl(api); // console.log(response.data); // 返回的是Buffer var data = JSON.parse(response.data); // 把Buffer类型转转换成对象 // console.log(data); return data.result; } // 获取新闻详情 async getNewsContent(aid){ const { ctx, config } = this var api = config.api + 'appapi.php?a=getPortalArticle&aid=' + aid; var response = await ctx.curl(api); var data = JSON.parse(response.data); //把Buffer类型转转换成对象 return data.result; } } module.exports = NewsService;
  • 添加app/controller/news.js文件
'use strict'; const Controller = require('egg').Controller; class NewsController extends Controller { async index() { const { ctx, service } = this; // 获取数据显示到新闻页面 var list = await service.news.getNewsList(); await ctx.render('news/index',{ list }) } async detail(){ const { ctx, service } = this // 获取get传值 // var aid = ctx.query.aid; var aid = ctx.params.id var list = await service.news.getNewsContent(aid); await ctx.render('news/detail', { list: list[0] }) } } module.exports = NewsController;
  • 添加app/view/news/index.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> <h2>新闻列表数据</h2> <ul> <%for(var i=0;i<list.length;i++){%> <li> <a href="/news/detail/<%=list[i].aid%>"><%=list[i].title%></a> <span>---<%=list[i].dateline%></span> </li> <%}%> </ul> </body> </html>
  • 添加app/view/news/detail.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> <link rel="stylesheet" href="/public/css/basic.css"> </head> <body> <div class="content"> <h2><%=list.title%></h2> <div> <%-list.content%> </div> </div> </body> </html>

更多HttpClient信息参考

框架扩展-extend

框架提供了多种扩展点扩展自身的功能:

  • Application:对应app/extend/application.js文件
  • Context:对应app/extend/context.js文件
  • Request:对应app/extend/request.js文件
  • Response:对应app/extend/response.js文件
  • Helper:对应app/extend/helper.js文件

在开发中,我们既可以使用已有的扩展API来方便开发,也可以对以上对象进行自定义扩展,进一步加强框架的功能。

  • app/目录下新建extend/目录

  • app/extend/目录下新建application.js文件

/* 外部可以通过 this.app.foo() */ module.exports = { foo(param) { // this 就是 app 对象,在其中可以调用 app 上的其他方法,或访问属性 return this.config.api; }, };
  • app/extend/目录下新建context.js文件
module.exports={ getHost(){ // this 就是 ctx 对象,在其中可以调用 ctx 上的其他方法,或访问属性 return this.request.host; } }
  • app/extend/目录下新建request.js文件
/* 外部可以通过 this.ctx.request.foo() */ module.exports = { foo(param) { // console.log(this); return this.header.host; }, };
  • app/extend/目录下新建helper.js文件
// 扩展里面引入第三方模块 /* https://www.npmjs.com/package/silly-datetime 1.npm i silly-datetime --save 2、var sd = require('silly-datetime'); */ var sd = require('silly-datetime'); module.exports = { formatTime(param) { // this 是 helper 对象,在其中可以调用其他 helper 方法 // this.ctx => context 对象 // this.app => application 对象 // console.log(new Date(param)); //格式化日期 param(时间戳) return sd.format(new Date(param*1000), 'YYYY-MM-DD HH:mm'); }, getHelperData(){ return '我是helper里面的数据' } };
  • 修改app/controller/home.js文件,使用这些自定义的扩展
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; //调用extend里面扩展的application console.log(app.foo()); //调用extend里面扩展的ctx console.log(ctx.getHost()); // 调用extend 扩展request的方法 console.log(ctx.request.foo()); //调用extend里面扩展的helper的方法 console.log(ctx.helper.getHelperData()); await ctx.render('home') } } module.exports = HomeController;
  • 修改app/view/news/index.html文件。使用helper扩展formatTime
<!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> <h2>新闻列表数据</h2> <ul> <%for(var i=0;i<list.length;i++){%> <li> <a href="/news/detail/<%=list[i].aid%>"><%=list[i].title%></a> <!-- <span>---<%=list[i].dateline%></span> --> <span>---<%=helper.formatTime(list[i].dateline)%></span> </li> <%}%> </ul> </body> </html>

更多框架扩展信息参考

中间件-middleware

中间件:匹配路由前、匹配路由完成做的一系列的操作。
Egg是基于Koa实现的,所以Egg的中间件形式和Koa的中间件形式是一样的,都是基于洋葱圈模型

一般来说中间件也会有自己的配置。
在框架中,一个完整的中间件是包含了配置处理的。
我们约定一个中间件是一个放置在app/middleware目录下的单独文件,它需要exports一个普通的function,接受两个参数:

  • options: 中间件的配置项,框架会将app.config[${middlewareName}] 传递进来
  • app: 当前应用Application的实例
  • app/目录下新建middleware/目录

  • app/middleware/目录下新建printdate.js文件(打印时间)

/* options: 中间件的配置项,框架会将 app.config[${middlewareName}] 传递进来。 app: 当前应用 Application 的实例。 配置中间件 */ module.exports = (options, app) => { console.log(options); //返回一个异步的方法 return async function printDate(ctx, next) { console.log(new Date()); await next(); } };
  • app/middleware/目录下新建forbidip.js文件(禁止指定的IP访问)
module.exports = (options, app) => { //返回一个异步的方法 return async function forbidIp(ctx, next){ // 要屏蔽的ip : 1.从数据库获取 2、从参数传入 var forbidips = options.forbidips; // 获取客户端的ip var clientIp = ctx.request.ip; // some 和 forEach 相似 var hasIp = forbidips.some(val => { if (val == clientIp) { return true; } }) if (hasIp) { //屏蔽 ctx.status = 403; ctx.body='您的ip已经被屏蔽'; } else { await next(); } } };
  • 修改config/config.default.js文件,添加配置当前项目需要使用的中间件以及中间件的参数
// ... module.exports = appInfo => { // ... // add your middleware config here config.middleware = ['printdate', 'forbidip']; // 给printdate中间件传入的参数 config.printdate = { aaa: 'aaaaaa' } config.forbidip={ forbidips:[ '127.0.0.1', '192.168.0.10', // '::1' ] } // ... };

更多中间件信息参考

表单

表单提交需要注意防范CSRF攻击

方法一

  • 修改app/router.js文件,添加路由
// ... module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.get('/form1', controller.home.form1); // ... };
  • 修改app/controller/home.js文件
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; await ctx.render('home') } async form1() { const { ctx } = this; // this.ctx.csrf 用户访问这个页面的时候生成一个密钥 await ctx.render('form1', { csrf: ctx.csrf }) } // 接收post提交的数据 this.ctx.request.body async add() { const { ctx } = this console.log(ctx.request.body); ctx.body = ctx.request.body; } } module.exports = HomeController;
  • app/view/目录下新建form1.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>表单</title> </head> <body> <form action="/add?_csrf=<%=csrf%>" method="POST"> 用户名: <input type="text" name="username" /> <br><br> 密 码: <input type="password" name="password" type="password" /> <br><br> <button type="submit">提交</button> </form> </body> </html>

方法二

  • 修改app/router.js文件,添加路由
// ... module.exports = app => { const { router, controller } = app; router.get('/', controller.home.index); router.get('/form2', controller.home.form2); // ... };
  • 修改app/controller/home.js文件
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; await ctx.render('home') } async form2() { const { ctx } = this; await ctx.render('form2', { // 也可以使用 middleware/auth 中间件全局设置 csrf: ctx.csrf }) } // 接收post提交的数据 this.ctx.request.body async add() { const { ctx } = this console.log(ctx.request.body); ctx.body = ctx.request.body; } } module.exports = HomeController;
  • app/view/目录下新建form2.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>表单</title> </head> <body> <form action="/add" method="POST"> <input type="hidden" name="_csrf" value="<%=csrf%>"> 用户名: <input type="text" name="username" /> <br><br> 密 码: <input type="password" name="password" type="password" /> <br><br> <button type="submit">提交</button> </form> </body> </html>

middleware/auth中间件全局设置方法如下:

  • app/middleware/目录下新建auth.js文件
module.exports=(option, app) => { return async (ctx,next) => { // 设置模板全局变量 ctx.state.csrf = ctx.csrf; await next(); } }
  • 修改config/config.default.js文件
// ... module.exports = appInfo => { // ... // add your middleware config here config.middleware = ['auth']; // ... };
  • 修改app/controller/home.js文件
// ... class HomeController extends Controller { // ... async form2() { const { ctx } = this; await ctx.render('form2', { // 这里已经使用 middleware/auth 中间件全局设置了,就不用在额外设置了 // csrf: ctx.csrf }) } // ... } // ...

更多表单相关信息参考:

Cookie

简介

cookie是存储于访问者的计算机中的变量。可以让我们用同一个浏览器访问同一个域名的时候共享数据

HTTP是无状态协议。简单地说,当你浏览了一个页面,然后转到同一个网站的另一个页面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次的访问,都是没有任何关系的

服务端可以通过响应头(set-cookie)将少量数据响应给客户端
浏览器会遵循协议将数据保存,并在下次请求同一个服务的时候带上(浏览器也会遵循协议,只在访问符合Cookie指定规则的网站时带上对应的Cookie来保证安全性)

方法:

  • 设置cookiectx.cookies.set(key, value, options)
  • 获取cookiectx.cookies.get(key, options)
  • 清除cookiectx.cookies.set(key, null)

options参数:

  • {Number} maxAge: 设置这个键值对在浏览器的最长保存时间。是一个从服务器当前时刻开始的毫秒数。
  • {Date} expires: 设置这个键值对的失效时间,如果设置了maxAgeexpires将会被覆盖。如果maxAgeexpires都没设置,Cookie将会在浏览器的会话失效(一般是关闭浏览器时)的时候失效。
  • {String} path: 设置键值对生效的URL路径,默认设置在根路径上(/),也就是当前域名下的所有URL都可以访问这个Cookie
  • {String} domain: 设置键值对生效的域名,默认没有配置,可以配置成只在指定域名才能访问。
  • {Boolean} httpOnly: 设置键值对是否可以被js访问,默认为true,不允许被js访问。
  • {Boolean} secure: 设置键值对只在HTTPS连接上传输,框架会帮我们判断当前是否在HTTPS连接上自动设置secure的值。
    除了这些属性之外,框架另外扩展了3个参数的支持
  • {Boolean} overwrite:设置key相同的键值对如何处理,如果设置为true,则后设置的值会覆盖前面设置的,否则将会发送两个set-cookie响应头。
  • {Boolean} signed:设置是否对Cookie进行签名,如果设置为true,则设置键值对的时候会同时对这个键值对的值进行签名,后面取的时候做校验,可以防止前端对这个值进行篡改。默认为true
  • {Boolean} encrypt:设置是否对Cookie进行加密,如果设置为true,则在发送Cookie前会对这个键值对的值进行加密,客户端无法读取到Cookie的明文值。默认为false

建议写法

设置cookie建议的写法:

ctx.cookies.set(key, value, { maxAge: 24 * 3600 * 1000, httpOnly: true, // by default it's true encrypt: true, // cookies are encrypted during network transmission }); ctx.cookies.get('frontend-cookie', { encrypt: true });

设置中文Cookie

  • 方法一:转码后存储,取出来后解码
console.log(new Buffer('hello, world!').toString('base64')); // 转换成 base64 字符串:aGVsbG8sIHdvcmxkIQ== console.log(new Buffer('aGVsbG8sIHdvcmxkIQ==', 'base64').toString()); // 还原 base64 字符串:hello, world!
  • 方法二:存储时加密存,取出来的时候也加密取
ctx.cookies.set(key, value, { maxAge: 24 * 3600 * 1000, httpOnly: true, // by default it's true encrypt: true, // cookies are encrypted during network transmission });

示例

  • 修改app/controller/home.js文件
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; /* cookie: 1.可以实现 同一个浏览器访问同一个域的时候 不同页面之间的数据共享 2、实现数据的持久化 (关闭浏览器重新打开以后数据还存在) 参数: 第一个参数:cookies的名称 第二个参数:cookies的值 第三个参数:配置 默认情况:cookies当浏览器关闭以后就销毁了 */ // ctx.cookies.set('username', 'zhangsan'); // 注意:默认情况下面 egg.js 里面的 cookie 没法设置中文 argument value is invalid (code: ERR_ASSERTION) // ctx.cookies.set('username','张三'); // ctx.cookies.set('username', 'zhagnsan', { // maxAge: 1000*3600*24, // cookie存储一天 设置过期时间后关闭浏览器重新打开cookie还存在 // httpOnly: true, // signed: true, // 对cookie进行签名 防止用户修改cookie // encrypt: true // 是否对cookie进行加密 如果cookie加密那么获取的时候要对cookie进行解密 // }); // 如果cookie加密以后就可以设置中文cookie (encrypt:true) // ctx.cookies.set("userinfo", '张三', { // maxAge: 1000*3600*24, // cookie存储一天 设置过期时间后关闭浏览器重新打开cookie还存在 // httpOnly: true, // signed: true, // 对cookie进行签名 防止用户修改cookie // encrypt: true // 是否对cookie进行加密 如果cookie加密那么获取的时候要对cookie进行解密 // }) ctx.cookies.set("userinfo", '张三', { maxAge: 1000*3600*24, // cookie存储一天 设置过期时间后关闭浏览器重新打开cookie还存在 httpOnly: true, signed: true, // 对cookie进行签名 防止用户修改cookie encrypt: true // 是否对cookie进行加密 如果cookie加密那么获取的时候要对cookie进行解密 }) ctx.cookies.set("name", '张三', { maxAge: 1000*3600*24, // cookie存储一天 设置过期时间后关闭浏览器重新打开cookie还存在 httpOnly: true, signed: true, // 对cookie进行签名 防止用户修改cookie encrypt: true // 是否对cookie进行加密 如果cookie加密那么获取的时候要对cookie进行解密 }) // cookies里面设置对象 JSON.stringify() JSON.parse() await ctx.render('home') } async loginOut(){ const { ctx } = this // 清理cookies ctx.cookies.set('userinfo', null); // ctx.cookies.set('userinfo', null,{ // maxAge:0 // }); ctx.redirect('/news'); /* 路由跳转 */ } // ... } module.exports = HomeController;
  • 修改app/controller/news.js文件
'use strict'; const Controller = require('egg').Controller; class NewsController extends Controller { async index() { const { ctx, service } = this; // // 获取cookie // var username = ctx.cookies.get('username'); // console.log(username) // // 获取加密的cookie // var userinfo = ctx.cookies.get('userinfo', { // encrypt:true // }); // console.log(userinfo) //获取cookie var name = ctx.cookies.get('name', { encrypt: true }); //获取加密的cookie var userinfo = ctx.cookies.get('userinfo', { encrypt:true }); console.log(name, userinfo) // ... await ctx.render('news/index',{ list }) } // ... } module.exports = NewsController;

更多Cookie信息参考

Session

简介

  • cookie数据存放在客户的浏览器上,session数据放在服务器上。
  • cookie没有session安全,别人可以分析存放在本地的cookie并进行cookie欺骗。
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能。考虑到减轻服务器性能方面,应当使用cookie
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20cookie
  • session的实现是基于cookie的,默认配置下,用户session的内容加密后直接存储在cookie中的一个字段中,用户每次请求我们网站的时候都会带上这个cookie,我们在服务端解密后使用

特别注意

  • 不要以_开头
  • 不能为isNew

示例

  • 修改app/controller/home.js文件
'use strict'; const Controller = require('egg').Controller; class HomeController extends Controller { async index() { const { ctx, config, app } = this; // 设置session ctx.session.username = '张三'; ctx.session.userinfo = { name: '李四', age: 20 } // 设置session的过期时间 修改session的默认参数 不建议用这样的方式 // ctx.session.maxAge = 5000; await ctx.render('home') } // ... } module.exports = HomeController;
  • 修改app/controller/news.js文件
'use strict'; const Controller = require('egg').Controller; class NewsController extends Controller { async index() { const { ctx, service } = this; var username = ctx.session.username; var userinfo = ctx.session.userinfo; console.log(username, userinfo) // 设置session的过期时间 修改session的默认参数 不建议用这样的方式 // this.ctx.session.maxAge = 5000; await ctx.render('news/index') } // ... } module.exports = NewsController;

更多Session信息参考


创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: