精华内容
下载资源
问答
  • egg框架安全

    2019-10-14 23:16:03
    0x00 egg框架简介与使用 一、简介 Egg 选择了 Koa 作为其基础框架,在它的模型基础上,进一步对它进行了一些增强。 官方网站:https://eggjs.org/zh-cn/intro/egg-and-koa.html 二、简单Demo 1、创建初始化一个...

    0x00 egg框架简介与使用

    一、简介

    Egg 选择了 Koa 作为其基础框架,在它的模型基础上,进一步对它进行了一些增强。

    官方网站:https://eggjs.org/zh-cn/intro/egg-and-koa.html

    二、简单Demo

    1、创建初始化一个egg项目

    $ npm init egg --type=simple
    $ npm i

    2、目录结构 

    egg-project
    ├── package.json
    ├── app.js (可选)
    ├── agent.js (可选)
    ├── app
    |   ├── router.js   //用于配置 URL 路由规则
    │   ├── 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

    3、在home.js中编写请求的处理与响应操作

    'use strict';
    
    const Controller = require('egg').Controller;
    const fs = require('fs');        //node.js 的文件模块 fs
    
    class HomeController extends Controller {
      async index() {
        const { ctx } = this;
        this.ctx.body = await fs.readFileSync(__dirname + '/../view/html/login.html').toString();
      }
    }
    
    module.exports = HomeController;

    返回一个html页面  

    4、在router.js编写路由 

    'use strict';
    
    /**
     * @param {Egg.Application} app - egg application
     */
    module.exports = app => {
      const { router, controller } = app;
      router.get('/homePage', controller.home.index);
    };
    

    5、运行程序

    $ npm run dev

    6、浏览器访问

     

    0x01 点击劫持

     点击劫持是指在一个Web页面下隐藏了一个透明的iframe(opacity:0),用外层假页面诱导用户点击,实际上是在隐藏的frame上触发了点击事件进行一些用户不知情的操作。

    假设自己服务器有如下页面login.html:

    <!DOCTYPE html>
    <html>
    <head> 
    <meta charset="utf-8"> 
    <title>test</title> 
    </head> 
    <body>
    <form action="demo_form.asp">
      First name: <input type="text" name="fname"><br>
      Last name: <input type="text" name="lname"><br>
      <input type="submit" value="提交">
    </form>
    </body>
    </html>

     服务器同域下有个A页面嵌入了login.html页面:

    <!DOCTYPE html>
    <html>
    <head> 
    <meta charset="utf-8"> 
    <title>test</title> 
    </head> 
    <body>
    
    <iframe src="http://127.0.0.1:7001/homePage">
      <p>您的浏览器不支持  iframe 标签。</p>
    </iframe>
    
    </body>
    </html>

     访问该页面能够把login页面嵌入,因为是同域下的,没有风险,egg框架允许嵌入。

    把上述A页面拷贝到本机其他地方,浏览器打开该页面,则无法获取:

    所以egg框架默认开启了xframe的保护,默认为SAMEORIGIN配置。

    可以通过在config.default.js文件中配置xframe关闭保护(不建议),如下所示:

    此时再次打开本地的A页面,能够把服务器中的页面嵌入。

     

    防护建议:不主动配置xframe,并enable属性设置为false,否则有点击劫持的安全问题。保持默认配置即可。

    0x02 URL钓鱼

    服务端未对传入的跳转 url 变量进行检查和控制,可能导致可恶意构造任意一个恶意地址,诱导用户跳转到恶意网站。 由于是从可信的站点跳转出去的,用户会比较信任,所以跳转漏洞一般用于钓鱼攻击,通过转到恶意网站欺骗用户输入用户名和密码盗取用户信息,或欺骗用户进行金钱交易; 也可能引发的 XSS 漏洞(主要是跳转常常使用 302 跳转,即设置 HTTP 响应头,Locatioin: url,如果 url 包含了 CRLF,则可能隔断了 HTTP 响应头,使得后面部分落到了 HTTP body,从而导致 XSS 漏洞)。

    egg框架会产生网页重定向的用法有:ctx.redirect(url)ctx.unsafeRedirect(url)

    ctx.redirect(url)会经过配置的白名单的校验后再进行跳转,如果domainWhiteList 为空则与ctx.unsafeRedirect(url)跳转一样不进行校验。

    下面是重定向网页的代码:

    此时是可以跳转到baidu的。没有白名单配置的效果和ctx.unsafeRedirect(url)一样

    为了防止URL钓鱼攻击,需要在使用ctx.redirect(url)的情况下配置可访问域的白名单,如下所示:

    此时重新访问该URL,显示该URL被禁止,达到URL重定向的安全

    防护建议:在进行网页重定向时需要调用ctx.redirect(url)函数并正确设置白名单domainWhiteList: ['domain']。

    0x03 反射型XSS防护

    反射型的 XSS 攻击,主要是由于服务端接收到客户端的不安全输入,在客户端触发执行从而发起 Web 攻击。比如:

    在某购物网站搜索物品,搜索结果会显示搜索的关键词。搜索关键词填入<script>alert('1')</script>, 点击搜索。页面没有对关键词进行过滤,这段代码就会直接在页面上执行,弹出 alert。

    框架提供了 helper.escape() 方法对字符串进行 XSS 过滤。

    const str = '><script>alert("abc") </script><';
    console.log(ctx.helper.escape(str));
    // 输出结果 => &gt;&lt;script&gt;alert(&quot;abc&quot;) &lt;/script&gt;&lt;

     研究一下helper.escape() 的编码机制,通过调试发现最终调用如下函数:

    function escapeHtml(string) {
      var str = '' + string;
      var match = matchHtmlRegExp.exec(str);
    
      if (!match) {
        return str;
      }
    
      var escape;
      var html = '';
      var index = 0;
      var lastIndex = 0;
    
      for (index = match.index; index < str.length; index++) {
        switch (str.charCodeAt(index)) {
          case 34: // "
            escape = '&quot;';
            break;
          case 38: // &
            escape = '&amp;';
            break;
          case 39: // '
            escape = '&#39;';
            break;
          case 60: // <
            escape = '&lt;';
            break;
          case 62: // >
            escape = '&gt;';
            break;
          default:
            continue;
        }
    
        if (lastIndex !== index) {
          html += str.substring(lastIndex, index);
        }
    
        lastIndex = index + 1;
        html += escape;
      }
    
      return lastIndex !== index
        ? html + str.substring(lastIndex, index)
        : html;
    }

    从上述代码可以看出,该函数对  "、&、 '、<、>五个字符进行了实体编码,基本能够防护大多数反射型XSS。

    防护建议1:当网站需要直接输出用户输入的结果时,请务必使用 helper.escape() 包裹起来。

    另外一种情况,网站输出的内容会提供给 JavaScript 来使用。这个时候需要使用 helper.sjs() 来进行过滤。

    helper.sjs() 用于在 JavaScript(包括 onload 等 event)中输出变量,会对变量中字符进行 JavaScript ENCODE, 将所有非白名单字符转义为 \x 形式,防止 XSS 攻击,也确保在 js 中输出的正确性。使用实例:

    const foo = '"hello"';
    
    // 未使用 sjs
    console.log(`var foo = "${foo}";`);
    // => var foo = ""hello"";
    
    // 使用 sjs
    console.log(`var foo = "${this.helper.sjs(foo)}";`);
    // => var foo = "\\x22hello\\x22";

    helper.sjs()最终实际调用如下函数:

    function escapeJavaScript(string) {
    
      const str = '' + string;
      const match = MATCH_VULNERABLE_REGEXP.exec(str);
    
      if (!match) {
        return str;
      }
    
      let res = '';
      let index = 0;
      let lastIndex = 0;
      let ascii;
    
      for (index = match.index; index < str.length; index++) {
        ascii = str[index];
        if (BASIC_ALPHABETS.has(ascii)) {
          continue;
        } else {
          if (map[ascii] === undefined) {
            const code = ascii.charCodeAt(0);
            if (code > 127) {
              continue;
            } else {
              map[ascii] = '\\x' + code.toString(16);//若当前字符位于黑名单中,则使用\x转义
            }
          }
        }
    
        if (lastIndex !== index) {
          res += str.substring(lastIndex, index);
        }
    
        lastIndex = index + 1;
        res += map[ascii];
      }
    
      return lastIndex !== index ? res + str.substring(lastIndex, index) : res;
    
    }

    防护建议2网站输出的内容会提供给 JavaScript 来使用。这个时候需要使用 helper.sjs() 来进行过滤

    还有一种情况,有时候我们需要在 JavaScript 中输出 json ,若未做转义,易被利用为 XSS 漏洞。框架提供了 helper.sjson() 宏做 json encode,会遍历 json 中的 key ,将 value 的值中,所有非白名单字符转义为 \x 形式,防止 XSS 攻击。同时保持 json 结构不变。 若存在模板中输出一个 JSON 字符串给 JavaScript 使用的场景,请使用 helper.sjson(变量名) 进行转义。

    输出如下所示: 

    白名单为大小写字母:

    abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ

    不在白名单内的字符按下述进行替换

    若没有替换的字符,则直接删除。代码如下所示:

    防护建议3需要在 JavaScript 中输出 json ,这个时候需要使用  helper.sjson() 来进行转义

    0x04 存储型XSS

    攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。这就意味着只要访问了这个页面的访客,都有可能会执行这段恶意脚本,因此储存型XSS的危害会更大。因为存储型XSS的代码存在于网页的代码中,可以说是永久型的。

    框架提供了 helper.shtml() 方法对字符串进行 XSS 过滤。将富文本(包含 HTML 代码的文本)当成变量直接在模版里面输出时,需要用到 shtml 来处理。 使用 shtml 可以输出 HTML 的 tag,同时执行 XSS 的过滤动作,过滤掉非法的脚本。默认情况下,使用以下白名单进行过滤,:

    function getDefaultWhiteList() {
    	return {
    	a: ["target", "href", "title"],
    	abbr: ["title"],
    	address: [],
    	area: ["shape", "coords", "href", "alt"],
    	article: [],
    	aside: [],
    	audio: ["autoplay", "controls", "loop", "preload", "src"],
    	b: [],
    	bdi: ["dir"],
    	bdo: ["dir"],
    	big: [],
    	blockquote: ["cite"],
    	br: [],
    	caption: [],
    	center: [],
    	cite: [],
    	code: [],
    	col: ["align", "valign", "span", "width"],
    	colgroup: ["align", "valign", "span", "width"],
    	dd: [],
    	del: ["datetime"],
    	details: ["open"],
    	div: [],
    	dl: [],
    	dt: [],
    	em: [],
    	font: ["color", "size", "face"],
    	footer: [],
    	h1: [],
    	h2: [],
    	h3: [],
    	h4: [],
    	h5: [],
    	h6: [],
    	header: [],
    	hr: [],
    	i: [],
    	img: ["src", "alt", "title", "width", "height"],
    	ins: ["datetime"],
    	li: [],
    	mark: [],
    	nav: [],
    	ol: [],
    	p: [],
    	pre: [],
    	s: [],
    	section: [],
    	small: [],
    	span: [],
    	sub: [],
    	sup: [],
    	strong: [],
    	table: ["width", "border", "align", "valign"],
    	tbody: ["align", "valign"],
    	td: ["width", "rowspan", "colspan", "align", "valign"],
    	tfoot: ["align", "valign"],
    	th: ["width", "rowspan", "colspan", "align", "valign"],
    	thead: ["align", "valign"],
    	tr: ["rowspan", "align", "valign"],
    	tt: [],
    	u: [],
    	ul: [],
    	video: ["autoplay", "controls", "loop", "preload", "src", "height", "width"]
    	};
    	}

    例如白名单 中a: ["target", "href", "title"]  表示可以使用html标签<a>,并且标签中可以使用属性"target", "href", "title"。除了上述白名单之外的标签和属性egg框架将会删除。特别的config.helper.shtml.domainWhiteList: [] 可拓展 href 和 src 中允许的域名白名单, 默认为本域"http://localhost:7001"。所以如下代码href将被删除:

     ctx.app.config.security.domainWhiteList=["baidu.com"]/ 可拓展 href 和 src 中允许的域名白名单为baidu的。代码如下所示:

        async xss() {
        const { ctx } = this;
    	const value = '<a href="http://www.baidu.com">google</a><script>alert("hello")</script>';
    	ctx.app.config.security.domainWhiteList=["baidu.com"]//会加.号进行匹配
    	var data =  ctx.helper.shtml(value);
    	this.ctx.body = data;
      }
      

    以下是内部白名单域校验代码:

     

    访问该URL,href属性被保留,点击google能够跳转到百度页面:

     0x05 Web 安全头防御XSS

    egg框架也提供了常见的用于指示浏览器防护XSS的方法-通过开启 Web 安全头。包括:

    1. CSP(Content Security Policy)。框架内支持 CSP 的配置,不过是默认关闭的,开启后可以有效的防止 XSS 攻击的发生,需要配置 CSP 。

    2. X-Download-Options:noopen。默认开启,禁用 IE 下下载框Open按钮,防止 IE 下下载文件默认被打开 XSS。

    3. X-Content-Type-Options:nosniff。禁用 IE8 自动嗅探 mime 功能例如 text/plain 却当成 text/html 渲染,特别当本站点 serve 的内容未必可信的时候。

    4. X-XSS-Protection。IE 提供的一些 XSS 检测与防范,默认开启

          xssProtection: {
            enable: true,
            value: '1; mode=block',
          },

       

    5. Strict-Transport-Security。默认关闭,如果需要开启https传输,需要开启。

    同样在配置文件中配置,例如CSP:

    exports.security = {
      csp: {
        match: '/example',
        policy: {
          //...
        },
      },
    };

    针对/example路由设置内容安全策略,csp策略按需进行配置 。其余的见下文如何配置。

    0x06 参数污染HPP

    HPP是HTTP Parameter Pollution的缩写,意为HTTP参数污染。
    原理:浏览器在跟服务器进行交互的过程中,浏览器往往会在GET/POST请求里面带上参数,这些参数会以 名称-值 对的形势出现,通常在一个请求中,同样名称的参数只会出现一次。但是在HTTP协议中是允许同样名称的参数出现多次的。比如下面这个链接:http://www.baidu.com?name=aa&name=bb ,针对同样名称的参数出现多次的情况,不同的服务器的处理方式会不一样。有的服务器是取第一个参数,也就是name=aa。有的服务器是取第二个参数,也就是name=bb。有的服务器两个参数都取,也就是name=aa,bb 。这种特性在绕过一些服务器端的逻辑判断时,非常有用。

    HPP漏洞,与Web服务器环境、服务端使用的脚本有关。如下是不同Web服务器对于出现多个参数时的选择。


    而在egg框架中,会强制使用第一个参数,用户只要关心通过request获取对应name的值即可,并做好校验防护。

    0x07 XST防护

    "Cross-Site-Tracing"简称为XST,如果开发者在设置cookie属性时配置了httponly属性,那么通过XSS攻击就无法读取cookie数据,那么如果服务器支持TRACE请求并且允许跨域的话,那么还是可以读取到cookie数据的。

    XST介绍:https://www.owasp.org/index.php/XST

    egg框架中已经禁止了 trace,track,options 三种危险类型请求。

    0x08 SSRF防护

    SSRF漏洞:(服务端请求伪造)是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)。SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。利用的是服务端的请求伪造。ssrf是利用存在缺陷的web应用作为代理攻击远程和本地的服务器。

    框架在 ctxapp 和 agent 上都提供了 safeCurl 方法,在发起网络请求的同时会对指定的内网 IP 地址过滤,除此之外,该方法和框架提供的 curl 方法一致。

    ctx.safeCurl(url, options)
    app.safeCurl(url, options)
    agent.safeCurl(url, options)

    直接调用 safeCurl 方法其实并没有任何作用,还需要配合安全配置项。

    • ipBlackList(Array) - 配置内网 IP 名单,在这些网段内的 IP 地址无法被访问。
    • checkAddress(Function) - 直接配置一个检查 IP 地址的函数,根据函数的返回值来判断是否允许在 safeCurl 中被访问,当返回非 true 时,该 IP 无法被访问。checkAddress 优先级高于 ipBlackList
    // config/config.default.js
    exports.security = {
      ssrf: {
        ipBlackList: [
          '10.0.0.0/8', // 支持 IP 网段
          '0.0.0.0/32',
          '127.0.0.1',  // 支持指定 IP 地址
        ],
        // 配置了 checkAddress 时,ipBlackList 不会生效
        checkAddress(ip) {
          return ip !== '127.0.0.1';
        },
      },
    };

    0x09 CSRF机制

    使用egg提供的CSRF套件

    0x10前文各项安全配置案例

    一个完整的在config.default.js中对exports.security进行安全配置例子:

    /**
       * security options
       * @member Config#security
       * @property {String} defaultMiddleware - default open security middleware
       * @property {Object} csrf - whether defend csrf attack
       * @property {Object} xframe - whether enable X-Frame-Options response header, default SAMEORIGIN
       * @property {Object} hsts - whether enable Strict-Transport-Security response header, default is one year
       * @property {Object} methodnoallow - whether enable Http Method filter
       * @property {Object} noopen - whether enable IE automaticlly download open
       * @property {Object} nosniff -  whether enable IE8 automaticlly dedect mime
       * @property {Object} xssProtection -  whether enable IE8 XSS Filter, default is open
       * @property {Object} csp - content security policy config
       * @property {Object} referrerPolicy - referrer policy config
       * @property {Object} dta - auto avoid directory traversal attack
       * @property {Array} domainWhiteList - domain white list
       * @property {Array} protocolWhiteList - protocal white list
       */
      exports.security = {
        domainWhiteList: [],
        protocolWhiteList: [],
        defaultMiddleware: 'csrf,hsts,methodnoallow,noopen,nosniff,csp,xssProtection,xframe,dta',
    
        csrf: {
          enable: true,
    
          // can be ctoken or referer or all
          type: 'ctoken',
          ignoreJSON: false,
    
          // These config works when using ctoken type
          useSession: false,
          // can be function(ctx) or String
          cookieDomain: undefined,
          cookieName: 'csrfToken',
          sessionName: 'csrfToken',
          headerName: 'x-csrf-token',
          bodyName: '_csrf',
          queryName: '_csrf',
    
          // These config works when using referer type
          refererWhiteList: [
            // 'eggjs.org'
          ],
        },
    
        xframe: {
          enable: true,
          // 'SAMEORIGIN', 'DENY' or 'ALLOW-FROM http://example.jp'
          value: 'SAMEORIGIN',
        },
    
        hsts: {
          enable: false,
          maxAge: 365 * 24 * 3600,
          includeSubdomains: false,
        },
    
        dta: {
          enable: true,
        },
    
        methodnoallow: {
          enable: true,
        },
    
        noopen: {
          enable: true,
        },
    
        nosniff: {
          enable: true,
        },
    
        referrerPolicy: {
          enable: false,
          value: 'no-referrer-when-downgrade',
        },
    
        xssProtection: {
          enable: true,
          value: '1; mode=block',
        },
    
        csp: {
          enable: false,
          policy: {},
        },
    
        ssrf: {
          ipBlackList: null,
          checkAddress: null,
        },
      };

    详情可见:https://github.com/eggjs/egg-security/blob/master/config/config.default.js

     

    0x11 参考资料

    https://eggjs.org/zh-cn/intro/quickstart.html

    https://blog.csdn.net/starcrius/article/details/83750022

    https://www.jianshu.com/p/81dc757b25f1

    展开全文
  • 本项目使用egg框架重写,网络接口与原版的nideshop服务端几乎完全一样。可以配合进行联调(特别提醒:由于小程序sdk升级,原版的的用户登录功能已经无法使用,我对用户登录部分代码做了修改,修改后的) 本项目要点...
  • Egg框架一——Egg与koa

    千次阅读 2019-01-05 18:40:38
    Egg框架一——Egg与koa 一、Koa特点 koa中间件模型是``洋葱模型` 请求经过一个中间件会执行两侧 Context 上下文模型,相较于 request 和 response 而言更加符合语义。 优异的异常处理 async function onerror...

    Egg框架一——Egg与koa

    一、Koa特点

    1. koa中间件模型是``洋葱模型` 请求经过一个中间件会执行两侧

    2. Context 上下文模型,相较于 request 和 response 而言更加符合语义。

    3. 优异的异常处理

      async function onerror(ctx, next) {
        try {
          await next();
        } catch (err) {
          ctx.app.emit('error', err);
          ctx.body = 'server error';
          ctx.status = err.status || 500;
        }
      }
      

    二、Egg继承与Koa

    1. 扩展性更强:

      定义 app/extend/{application,context,request,response}.js 能快速扩展方法

    2. 插件:

      • extend:扩展基础对象的上下文,提供各种工具类、属性。
      • 一个插件可以有多个中间件组成 middleware
      • config:配置各个环境下插件自身的默认配置项。
    展开全文
  • 原生js运用egg框架写的一个小项目
  • node.js后台egg框架理解

    2020-02-10 18:14:52
    egg框架 egg理解 项目流程

    egg框架

    egg理解

    在这里插入图片描述

    项目流程

    在这里插入图片描述

    展开全文
  • EGG框架学习

    2021-01-09 13:09:57
    文章目录介绍特性环境搭建、创建、运行目录结构主要内容什么是MVC控制器(controller)服务(service)路由器(routes)项目实战演示使用egg-mongoose链接数据库配置 介绍 Eggjs是一个基于Koajs的框架,所以它应当属于框架...

    介绍

    Eggjs是一个基于Koajs的框架,所以它应当属于框架之上的框架,它继承了Koa的高性能优点,同时又加入了一些约束与开发规范,来规避Koajs框架本身的开发自由度太高的问题。

    Koajs是一个nodejs中比较基层的框架,它本身没有太多约束与规范,自由度非常高,每一个开发者实现自己的服务的时候,都有自己的“骚操作”。而egg为了适应企业开发,加了一些开发时的规范与约束,从而解决Koajs这种自由度过高而导致不适合企业内使用的缺点,Egg便在这种背景下诞生。

    ​ Egg是由阿里巴巴团队开源出来的一个“蛋”,为什么是个蛋?蛋是有无限可能的,鸡孵出的蛋生小鸡,恐龙孵出来的蛋就是恐龙,这也正更好的体现了egg最大的一个亮点“插件机制”,每个公司每个团队甚至单个开发者都可以在这之上孵化出最适合自己的框架。像阿里内部不同的部门之间都孵化出了合适自己的egg框架,如蚂蚁的chair,UC的Nut,阿里云的aliyun-egg等,可以看下面这张图。

    特性

    • 提供基于 Egg 定制上层框架的能力
    • 高度可扩展的插件机制
    • 内置多进程管理
    • 基于 Koa 开发,性能优异
    • 框架稳定,测试覆盖率高
    • 渐进式开发

    环境搭建、创建、运行

    
    $ npm  i egg-init -g
    $ npm init egg --type=simple
    $ npm i
    
    

    启动项目

    $ npm run dev
    $ gooopen http://localhost:7001
    

    目录结构

    egg-project
    ├── package.json
    ├── app.js (可选)
    ├── agent.js (可选)
    ├── app(项目开发目录)
    |   ├── router.js (用于配置 URL 路由规则)
    │   ├── 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
    
    

    主要内容

    什么是MVC

    • Model(模型) - 模型代表一个存取数据的对象。它也可以带有逻辑,在数据变化时更新控制器。
    • View(视图) - 视图代表模型包含的数据的可视化。
    • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

    1
    随着一些项目逐渐庞大,这样的设计造成了同一文件(或函数)的代码剧增,可维护性降低。同时,有一些可公用的业务操作也急需单独提取,因此形成了独立的业务层,分化了Controller部分。
    2
    至此,形成了常见的软件设计层次结构的主线路:

    • View:作为用户的 视图表现部分,常见的展示形式如浏览器作为载体的网页、原生APP应用界面、桌面应用界面等,用于提供用户界面以便收集、响应用户行为产生的数据;

    • Controller:作为 控制器层 部分,控制用户界面(View)的数据流转途径,主要行为包含接收用户数据请求、发送请求至业务层(Service)、获取业务层(Service)数据响应,将响应数据发送至用户界面(View),或生成相应的模板界面发送至用户;

    • Service:作为 业务处理层 部分,主要负责收集及对数据进行相应的运算处理,主要行为包含收集控制器请求数据、数据有效性验证、运算、请求数据模型(Model)、接收数据模型(Model)响应消息、响应结果至控制器等;

    • Model:作为 数据模型层 部分,主要用于将数据持久化(OUT)、查询持久化数据(IN),常见行为如对数据库进行操作、缓存数据库数据等;

    需要分别写出不同层的业务逻辑。

    控制器(controller)

    app/controller目录下面实现Controller
    实现一些逻辑的操作,也就是将数据写到页面

    'use strict';
    
    const Controller = require('egg').Controller;
    
    class HomeController extends Controller {
      async index() {
        const { ctx } = this;
        ctx.body = 'hi, egg';
      }
    }
    
    module.exports = HomeController;
    
    

    服务(service)

    主要操作数据库

    'use strict';
    
    const Service = require('egg').Service;
    
    class HomeService extends Service {
      async index() {
        return {ok:1}
      }
    }
    
    module.exports = HomeService;
    
    
    

    修改controller/home.js

    'use strict';
    
    const Controller = require('egg').Controller;
    
    class HomeController extends Controller {
      async index() {
        const {
          ctx,
          service
        } = this;
        const res = await service.home.index();
        ctx.body = res
      }
    }
    
    module.exports = HomeController;
    
    

    路由器(routes)

    'use strict';
    
    /**
     * @param {Egg.Application} app - egg application
     */
    module.exports = app => {
      const { router, controller } = app;
      router.get('/', controller.home.index);
    };
    
    

    项目实战演示

    针对用户表的增删改查操作

    案例基于mongoose非关系型数据库

    使用egg-mongoose链接数据库

    npm i egg-mongoose -S
    

    配置

    config/plugin.js

    exports.mongoose = {
      enable: true,
      package: 'egg-mongoose',
    };
    
    

    config/config.default.js

    config.mongoose = {
        url: "mongodb://127.0.0.1:27017/egg-test",
        options:{
            useUnifiedTopology: true,
            useCreateIndex:true
        }
    }
    
    
    

    创建用户模型
    model/user.js

    module.exports = app => {
      const mongoose = app.mongoose;
      const UserSchema = new mongoose.Schema({
        username: {
          type: String,
          unique: true,
          required: true
        },
        password: {
          type: String,
          required: true
        },
        avatar: {
          type: String,
          default: 'https://1.gravatar.com/avatar/a3e54af3cb6e157e496ae430aed4f4a3?s=96&d=mm'
        },
        createdAt: {
          type: Date,
          default: Date.now
        }
      })
      return mongoose.model('User', UserSchema);
    }
    
    

    创建用户
    router.js

     // 用户创建
      router.post('/api/user',controller.user.create);
    
    

    controller/user.js

    //创建用户
    async create() {
        const {
          ctx,
          service
        } = this;
        const payLoad = ctx.request.body || {};
        const res = await service.user.create(payLoad);
        ctx.body = {res};
     }
    
    

    service/user.js

    async create(payload) {
        const {
            ctx
        } = this;
        return ctx.model.User.create(payload);
    }
    
    

    获取所有用户

    router.js

    router.get('/api/user',controller.user.index);
    

    controller/user.js

    // 获取所有用户
    async index() {
        const {
            ctx,
            service
        } = this;
        const res = await service.user.index();
        ctx.body = res;
    }
    
    

    service/user.js

    async index() {
        const {
            ctx
        } = this;
        return ctx.model.User.find();
    }
    

    根据id获取用户详情
    router.js

    // 根据id获取用户详情
    router.get('/api/user/:id',controller.user.detail);
    

    controller/user.js

    async detail() {
        const id = this.ctx.params.id;
        const res = await this.service.user.detail(id);
        ctx.body = res;
    }
    
    

    service/user.js

    async detail(id){
       return this.ctx.model.User.findById({_id:id})
    }
    
    

    更新用户
    router.js

    // 修改用户
    router.put('/api/user/:id',controller.user.update);
    
    

    controller/user.js

    async update() {
        const id = this.ctx.params.id;
        const payLoad = this.ctx.request.body;
        // 调用 Service 进行业务处理
        await this.service.user.update(id, payLoad);
        // 设置响应内容和响应状态码
        ctx.body = {msg:'修改用户成功'};
    }
    
    

    service/user.js

    async update(_id, payLoad) {
        return this.ctx.model.User.findByIdAndUpdate(_id,payLoad);
    }
    
    

    删除用户
    router.js

    // 删除用户
    router.delete('/api/user/:id',controller.user.delete);
    
    

    controller/user.js

      async delete() {
        const id = this.ctx.params.id;
         // 调用 Service 进行业务处理
        await this.service.user.delete(id);
         // 设置响应内容和响应状态码
        ctx.body = {msg:"删除用户成功"};
      }
    
    

    service/user.js

    async delete(_id){
        return this.ctx.model.User.findByIdAndDelete(_id);
    }
    
    
    展开全文
  • 1-1 egg框架初始化项目

    2020-11-30 17:51:28
    egg框架使用方法1.项目初始化2.开发第一个api3.解除 安全威胁csrf的防范4.跨域 1.项目初始化 附上egg官方链接点击进入egg官网 (1).创建项目(打开cmd,进入想要创建项目的路径) mkdir egg-example //egg-example...
  • egg框架解决跨域 & 静态文件夹

    千次阅读 2019-03-12 16:38:13
    egg.js官方文档 ...解决egg框架跨域 web端访问服务器,存在跨域请求问题,egg作为服务端,需要开放请求域,方法如下: 1、安装egg-cors npm i egg-cors -S 2、在config/plugin.js声明 module.expor...
  • Egg框架三——基础功能

    千次阅读 2019-01-05 18:43:02
    Egg框架三——基础功能 一、Router 1. router支持路由方式 支持一下路由格式: router.verb('path-match', app.controller.action); router.verb('router-name', 'path-match', app.controller.action); router.verb...
  • 使用egg框架 1.快速生成项目 npm init egg --type=simple npm i 2.启动项目 npm run dev 3.安装ejs模板引擎 npm i egg-view-ejs --save 4.配置ejs模板引擎 (1)在config文件夹下面的config.default.js文件里写 ...
  • Node---egg框架基础(1)

    2020-08-03 19:46:20
    Node—egg框架基础(1) egg:为企业级框架和应用而生 ,可以降低开发和维护成本,遵循约定优于配置 ,按照统一的约定来进行项目开发。 egg框架约定的目录结构: egg-project ├── package.json ├── app.js (可选...
  • egg框架搭建

    2020-07-04 12:20:45
    首先安装nodejs 保证npm版本在6.1以上 创建项目文件夹 打开文件夹执行 npm init egg --type=simple 命令 然后执行 npm ...
  • egg ORM插件 执照
  • egg框架下载

    2019-10-04 14:47:50
    通过npm i egg-init -g下载后 通过mkdir showcase 查看目录 cd showcase 进入showcase文件夹 npm init egg --type=simple 下载 在进行回车 npm install进行下载 或cnpm install...
  • 使用 Egg 框架

    2019-07-30 11:54:04
    npm i -g egg-init egg-init name --type=simple cd name npm i app 文件夹下的 controller —— 控制层 service—— 数据(mysql) public —— 静态资源 http://localhost:7001/public/1.png view —— 测试接口 ...
  • Egg框架的使用

    2020-12-14 01:07:02
    egg是一个mvc框架 view 视图模板页面的展示 Controller控制器 负责处理一些业务逻辑的 service =>model(模型)和数据打交道,查询数据库,操作数据库数据,请求数据 整个过程是中间件在路由匹配之前或者路由匹配...
  • Egg框架二——渐进式开发 一、初始状体 插件写在extend里边(这时候只是扩展) example-app ├── app │ ├── extend │ │ └── context.js │ └── router.js ├── test │ └── index.test.js └──...
  • NodeJS框架学习-Egg框架

    千次阅读 2018-11-05 15:10:13
    第一步:下载安装nodejs ...本人是windows系统所以如图选择: 下载安装十分方便,环境变量也自动配置完成。 第二步:eggjs环境搭配,创建运行项目... egg官方文档网址:https://eggjs.org/zh-cn/ 生成项目: 1.npm i e...
  • Egg框架介绍

    千次阅读 2019-01-05 18:36:32
    一、前因 ...但是发现这篇教程可以提供方向,当遇到具体细节实现和原理时候还是摸不着头脑。 最后决定还是准备自己动手写,选择了“下一代的web框架” koa2(其实是跟express差不多,同一作者团...
  • Egg 框架模型简述 (一) 简单的骨架认知 1-1. 简述 1-2. 简单层级关系 1-3. 路由(Router) 1-4. 内置对象(Router) 1-5. 配置(Config) 1-6. 中间件(MiddleWare) 插件使用(Plugins) 持久层方案(egg-sequelize) ...
  • egg框架下中间件中显示当前状态(选中状态) 1、moddle中创建中间件文件 2、配置:config/config.default.js中进行配置 module.exports = (option, app) => { return async (ctx, next) => { let menus = [{...
  • Egg框架入门教程之示例合集 Awesome Egg.js 很棒的清单,精选了最好的Egg.js插件,工具,教程,文章等。欢迎公关! 内容 博客 文章 讲解 会议活动 外挂程式 应用领域 样板 构架 APM解决方案 非常...
  • 背景:用的egg框架 这个是service const CryptoJS = require("crypto-js/crypto-js"); //引入加密js 主要方法dingRemind async dingRemind() { const time = new Date().getTime(); //获取时间戳 const secret = ...
  • 内置对象 Request & Response 可以在 Context 的实例上获取到当前请求的 ...框架提供了一个 Controller 基类,并推荐所有的 Controller 都继承于该基类实现。这个 Controller 基类有下列属性: ctx - 当前请求的 Co
  • $ npm init egg --type=simple $ npm install $ npm run dev $ open http://localhost:7001 Node.js >= 8.0.0 required. Documentations Documentations Plugins Frameworks Examples Contributors How ...
  • Egg框架知识点1.目录结构和具体内容

    千次阅读 2018-08-15 16:00:30
    在这篇文章中,结合项目中的经历和EGG框架的目录结构进行详细整理。 目录结构: server(egg-project) ├── app | ├── router.js │ ├── controller │ | └── home.js │ ├── servi...
  • egg框架搭建项目

    2020-07-02 17:30:13
    打开文件夹执行 npm init egg --type=simple 命令 然后执行 npm i 运行 npm run dev 启动命令 项目文件结构如下 app 文件夹中为主要的操作文件(业务和逻辑代码全在其中) config 文件为配置文件夹(包含插件配置和...
  • Node—egg框架基础(3)–注册账户逻辑 众所周知,目前的大多数后台框架都是基于MVC模式的,egg也不例外,这里讲解一个使用MVC模式做的注册功能,其中涉及到了MVC以及数据库等。 首先了解一下什么是MVC: M:模型层...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 930
精华内容 372
关键字:

egg框架