成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Eggjs小試

waltr / 2048人閱讀

摘要:項(xiàng)目都很小,但為了進(jìn)一步了解,特意選擇了作為框架基礎(chǔ)開發(fā)后端服務(wù)。能將請(qǐng)求限制在同源網(wǎng)站,即只有擁有專有令牌的網(wǎng)站發(fā)送請(qǐng)求才會(huì)正確響應(yīng)。項(xiàng)目生產(chǎn)靜默部署,啟動(dòng)使用,停止使用。不足工具函數(shù)的訪問需要自己手動(dòng)添加擴(kuò)展另沒有寫測(cè)試,希望下次補(bǔ)上。

前言

這段時(shí)間,用Eggjs作為后端服務(wù)框架開發(fā)了幾個(gè)項(xiàng)目。項(xiàng)目都很小,但為了進(jìn)一步了解Eggjs,特意選擇了Eggjs作為框架基礎(chǔ)開發(fā)后端服務(wù)。期間也遇到過一些問題和坑,還有幾個(gè)值得注意的點(diǎn),下面來講一下我這段時(shí)間開發(fā)的總結(jié)。

Egg.js 為企業(yè)級(jí)框架和應(yīng)用而生 ,我們希望由 Egg.js 孕育出更多上層框架,幫助開發(fā)團(tuán)隊(duì)和開發(fā)人員降低開發(fā)和維護(hù)成本。

這個(gè)是Eggjs文檔對(duì)Eggjs的解釋,關(guān)于Eggjs的詳細(xì)介紹和使用請(qǐng)點(diǎn)解前面的地址;相對(duì)于Egg.js 1.x版本的文檔,已經(jīng)有很大的改進(jìn)了,很多關(guān)鍵的地方都可以比較完整講解和帶有代表性的實(shí)例。

步驟 開始

用的Egg.js版本是2.2.1,對(duì)環(huán)境有一定的要求,本人用的配置如下:

操作系統(tǒng):macOS

運(yùn)行環(huán)境:v9.8.0

使用腳手架快速創(chuàng)建項(xiàng)目:

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

項(xiàng)目安裝完畢,啟動(dòng)項(xiàng)目:

$ npm run dev
$ open localhost:7001

至此,項(xiàng)目順利建立及啟動(dòng)完畢。

項(xiàng)目結(jié)構(gòu):(摘自文檔)

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

上述目錄也是一個(gè)給開發(fā)者一個(gè)目錄創(chuàng)建的指南,但按照文檔建立的項(xiàng)目目錄結(jié)構(gòu)沒有那么全,基本上標(biāo)注為“可選”的都是初始沒有的,在/config目錄里也只有plugin.jsconfig.default.js兩個(gè)文件,其他文件要自己根據(jù)需求創(chuàng)建。

建立控制器Controller

初始項(xiàng)目里會(huì)有一個(gè)示例Controller,在創(chuàng)建一個(gè)新的Controller可以參考/app/controller/home.js的示例,一般而言,推薦使用module.exports暴露出一個(gè)類或者參數(shù)為app返回一個(gè)類的函數(shù)(文檔示例中為箭頭函數(shù),其他方式?jīng)]試過不清楚),類里面包含著這塊業(yè)務(wù)的一些操作,下面在控制器文件目錄/app/controller/里新建一個(gè)文件名為user.js的控制器文件:

// 繼承egg的控制器
const Controller = require("egg").Controller;
class UserController extends Controller {
  async index() {
    const { ctx } = this;
    const { name } = ctx.request.body;
    ctx.body = `hi, ${name}`;
  }
  async getUserById() {
     const { userId } = this.ctx.request.body;
     // 使用業(yè)務(wù)函數(shù)查詢用戶信息
     const userInfo = await this.service.user.findById(userId);
     this.ctx.body = {
         msgCode: 0,
         message: "成功",
         data: userInfo
     };
  }
}
// 注意:一定要將控制器暴露出去,否則請(qǐng)求的時(shí)候會(huì)報(bào)找不到該controller的錯(cuò)誤;
module.exports = UserController;
添加路由

路由代碼在/app目錄之下,文件名router.js,添加路由的代碼如下:

// 參數(shù)app為全局應(yīng)用的對(duì)象
module.exports = app => {
    const { router, controller, middleware } = app;
    // 在這里controller相當(dāng)于app下的controller文件目錄,user為user.js,index為控制器類的index方法
    router.get("/", controller.user.index); 
};
編寫業(yè)務(wù)

通常,controller主要處理數(shù)據(jù)的結(jié)構(gòu)和處理返回的結(jié)果,具體的涉及的業(yè)務(wù)由service業(yè)務(wù)類方法完成,編寫service,在目錄/app/service/下建立user.js文件,并編寫代碼:

// 同樣要繼承egg的Service類
const Service = require("egg").Service;
class UserService extends Service {
    // 根據(jù)用戶id查找用戶
    async findUserById(id) {
        const mysql = this.app.mysql;
        const result = await mysql.get("users", { id });
        return result;
    }
}
module.exports = UserService;
添加插件

eggjs simple 版本旨在根據(jù)業(yè)務(wù)需求添加eggjs的插件來搭建上層框架。在本人開發(fā)過程中,用到的一些插件做簡(jiǎn)要說明。

插件安裝:

$ npm i --save egg-pluginName

在文件/config/plugin.js添加配置:

exports.pluginName = {
  enable: true,
  package: "egg-pluginName",
};

需要插件初始化配置的情況下,修改/config/config.default.js

config.pluginName = {
    // 配置項(xiàng)
};
egg-mysql

因使用mysql數(shù)據(jù)庫,需要一個(gè)nodejs對(duì)mysql的操作庫,基于eggjs選擇了egg-mysql ,操作文檔點(diǎn)擊這里?;镜臄?shù)據(jù)庫增刪查改都能操作,寫起來還挺方便,但是有個(gè)需求,編寫某個(gè)接口,返回當(dāng)前用戶某一段時(shí)間的數(shù)據(jù),這就比較蛋疼了,找了很久,就連egg-mysql封裝的庫ali-rds查看了源碼也找不到這類方法,無奈之下,只能通過組織原生的mysql查詢語句去動(dòng)態(tài)拼湊,雖然不推薦,不過如果找到更好的方法,還是愿意改寫的。

查詢指定日期數(shù)據(jù)的mysql相關(guān)參考資料:

http://www.jb51.net/article/1...

https://www.cnblogs.com/benef...

https://www.cnblogs.com/softi...

egg-redis
redis相當(dāng)于基于內(nèi)存的一個(gè)微型數(shù)據(jù)庫,其存取速度非常快,代碼執(zhí)行的時(shí)候幾乎感覺不到阻塞,這里使用egg-redis作為項(xiàng)目對(duì)redis的操作庫,文檔點(diǎn)擊這里。文檔說明解析了基本的存取和設(shè)置操作,對(duì)于較為復(fù)雜的操作只能通過查看redis的官方文檔,對(duì)應(yīng)的命令小寫即為方法名:
redis命令DECR,對(duì)應(yīng)的方法使用:
// /app/controller/user.js
const value = await this.app.redis.decr(keyName);
擴(kuò)展內(nèi)置對(duì)象

添加過幾個(gè)插件之后,發(fā)現(xiàn)其中的源代碼都是以擴(kuò)展內(nèi)置對(duì)象的方式去掛載相關(guān)的庫或者插件的。

ctx

文檔原文:“一般來說屬性的計(jì)算在同一次請(qǐng)求中只需要進(jìn)行一次,那么一定要實(shí)現(xiàn)緩存,否則在同一次請(qǐng)求中多次訪問屬性時(shí)會(huì)計(jì)算多次,這樣會(huì)降低應(yīng)用性能。

推薦的方式是使用 Symbol + Getter 的模式?!?/p>

const jwt = require("jsonwebtoken");
const JWT = Symbol("Context#jwt");
module.exports = {
  get jwt() {
    if (!this[JWT]) {
      this[JWT] = jwt;
    }
    return this[JWT];
  }
};

第一次擴(kuò)展cxt對(duì)象的時(shí)候,不明白為何要使用Symbol + Getter的模式,后來基于這個(gè)問題,查找資料,發(fā)現(xiàn)這種方式更能避免和其他屬性名發(fā)生沖突,上述代碼中,ctxjwt定義為只讀方式。在方便維護(hù)的同時(shí),生成一個(gè)帶有命名空間(Context#jwt)字符串描述的Symbol實(shí)例數(shù)據(jù), 作為ctx的屬性,通過只讀屬性jwt來獲取內(nèi)部的JWT屬性。
PS:

ctx.JWT == ctx[JWT] // false

關(guān)于Symbol的介紹和使用請(qǐng)參考阮一峰的ES6。

app

在擴(kuò)展app對(duì)象的時(shí)候,遇到個(gè)問題,就是如果需要獲取ctx怎么辦?
查找文檔,找到了在擴(kuò)展app對(duì)象時(shí),只需要在函數(shù)體里添加一句代碼:

const ctx = app.createAnonymousContext();

就可以獲取ctx對(duì)象,這對(duì)于使用其他函數(shù)提供了一道橋梁。

編寫中間件
eggjs的中間件處理流程遵循koa的洋蔥式請(qǐng)求模型
中間件的寫法:
module.exports = options => {
    return async function middleWareFunctionName (ctx, next) {
        // 控制器之前業(yè)務(wù)處理代碼
        // ...
        await next();
        //控制器之后業(yè)務(wù)處理代碼
        // ...
    }
}

中間件以返回一個(gè)處理業(yè)務(wù)的函數(shù)為主體,函數(shù)接收兩個(gè)參數(shù):ctx、next。ctx則是請(qǐng)求級(jí)別的對(duì)象,next()方法可以讓請(qǐng)求進(jìn)入下一個(gè)步驟。特別注意的是:在一個(gè)控制器中,有對(duì)請(qǐng)求到達(dá)下一步之前做一些操作的,可以控制next()在代碼流程中的位置,其后也可以處理請(qǐng)求之后的操作。

制定定時(shí)任務(wù)

eggjs寫定時(shí)任務(wù)也是非常簡(jiǎn)單的,關(guān)注于業(yè)務(wù)代碼,加以簡(jiǎn)單的配置,即可使用定時(shí)任務(wù)。
下面是一個(gè)簡(jiǎn)單的定時(shí)統(tǒng)計(jì)業(yè)務(wù)數(shù)據(jù)的定時(shí)任務(wù):

const Subscription = require("egg").Subscription;

class Statistics extends Subscription {
  // 通過 schedule 屬性來設(shè)置定時(shí)任務(wù)的執(zhí)行間隔等配置
  static get schedule() {
    return {
      cron: "00 59 23 * * *", // 秒 分 時(shí) 日 月 年
      // interval: "10s", // 設(shè)置時(shí)間間隔觸發(fā),單位s為秒,ms為毫秒
      type: "worker", // all 指定所有的 worker 都需要執(zhí)行, worker 為某一個(gè) worker 執(zhí)行
    };
  }

  // subscribe 是真正定時(shí)任務(wù)執(zhí)行時(shí)被運(yùn)行的函數(shù)
  async subscribe() {
   // 定時(shí)任務(wù)業(yè)務(wù)代碼
   // ...
  }
}

module.exports = Statistics;

在程序啟動(dòng)的時(shí)候,就會(huì)在配置的指定時(shí)機(jī)執(zhí)行相關(guān)的業(yè)務(wù)代碼。

配置(待補(bǔ)充) csrf的討論

eggjsv2.x版本之后默認(rèn)開啟了csrf插件,已確?;?b>cookie存儲(chǔ)驗(yàn)證信息的網(wǎng)站信息安全。

csrf能將請(qǐng)求限制在同源網(wǎng)站,即只有擁有“專有令牌”的網(wǎng)站發(fā)送請(qǐng)求才會(huì)正確響應(yīng)。此處容易與jwt的作用混淆,可以看看這篇文章。

跨域
使用egg-cors;
前后端分離用戶驗(yàn)證
使用jwt驗(yàn)證

jwt則在認(rèn)證方式上跟csrf上有所不同,jwt可以在不使用cookie的情況下,以token的方式在前后端交互數(shù)據(jù)的body里傳輸,也可以在header里設(shè)置相關(guān)信息,詳細(xì)可以參考這篇文章。

日志(待補(bǔ)充)
類的寫法
遠(yuǎn)程機(jī)開發(fā)部署
文檔中,有《應(yīng)用部署》一文,里面介紹的很詳細(xì)的。使用egg-script插件啟動(dòng)生產(chǎn)環(huán)境中的應(yīng)用程序。項(xiàng)目生產(chǎn)靜默部署,啟動(dòng)使用npm start,停止使用npm stop。另,在開發(fā)環(huán)境里想要使用pm2管理進(jìn)程后臺(tái)啟動(dòng),--watch會(huì)不斷打印控制臺(tái)日志,原因不清楚。
生產(chǎn)環(huán)境部署

啟動(dòng)命令:

$ npm install --production
$ npm start

停止命令:

$ npm stop
總結(jié) 優(yōu)點(diǎn)
使用eggjs開發(fā)企業(yè)級(jí)應(yīng)用還是相當(dāng)方便的,雖然說要根據(jù)需求裝,但安裝和配置步驟非常簡(jiǎn)單,很多有用的業(yè)務(wù)配置都能夠很方便快速配置好,還可以區(qū)分環(huán)境,項(xiàng)目結(jié)構(gòu)和調(diào)用方式很合理。
不足
工具函數(shù)的訪問需要自己手動(dòng)添加擴(kuò)展
沒有寫測(cè)試,希望下次補(bǔ)上。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95471.html

相關(guān)文章

  • Eggjs下Restful API的實(shí)現(xiàn)

    摘要:今天就簡(jiǎn)要說說下的實(shí)現(xiàn)。主要的原因是的文檔寫的不太清楚,方便新人快速上手。導(dǎo)致我們一目十行去掃文檔的時(shí)候,有時(shí)總會(huì)覺得有些莫名,的實(shí)現(xiàn)就是其中之一。其實(shí)這和我本身對(duì)的了解不深入有關(guān),但是也沒有文檔和我說實(shí)現(xiàn)啊。 這兩天真的是宅的骨頭都發(fā)霉了,春困秋乏夏打盹,也是醉了。今天就簡(jiǎn)要說說eggjs下Restful API的實(shí)現(xiàn)。主要的原因是egg的文檔寫的不太清楚,方便新人快速上手。話說eg...

    linkin 評(píng)論0 收藏0
  • 造輪子 - EGGJS的MySQL操作庫

    摘要:最近學(xué)習(xí),學(xué)習(xí)過程中使用官方推薦的庫,感覺官方庫不太好用,基礎(chǔ)的沒問題。介紹這個(gè)輪子其實(shí)是很早以前就造好的,主要參考的數(shù)據(jù)庫操作方式。將設(shè)置表名設(shè)置查詢字段聯(lián)表等操作進(jìn)行鏈?zhǔn)讲僮鳎o人一種語義化操作數(shù)據(jù)庫的感覺。 最近學(xué)習(xí)eggjs,學(xué)習(xí)過程中使用官方推薦的MySQL庫,感覺官方庫不太好用,基礎(chǔ)的CURD沒問題。但是復(fù)雜點(diǎn)的操作就不行了,雖然官方還有一個(gè)egg-sequelize,但是...

    Alex 評(píng)論0 收藏0
  • 記一次eggjs+axios傳輸multipart的糾錯(cuò)過程

    摘要:總所周知,的策略讓每次都要發(fā)送碼驗(yàn)證,為了方便,我在的里作了前置攔截。結(jié)果不幸從此發(fā)生最開始沒有看官方文檔,以為應(yīng)該加在里面,又沒有考慮到要上傳格式的文檔,所以直接結(jié)果發(fā)送的是。這很正常,閱讀源碼知為時(shí)會(huì)自動(dòng)添加的頭。不加又以上傳了。 總所周知,egg的csrf策略讓post每次都要發(fā)送token碼驗(yàn)證,為了方便,我在axios的interceptor里作了前置攔截。 結(jié)果不幸從此發(fā)生...

    CarterLi 評(píng)論0 收藏0
  • eggjs】部署egg時(shí)碰到的日志權(quán)限問題

    摘要:前兩天將一個(gè)部署到服務(wù)器時(shí),用就是啟動(dòng)不了,錯(cuò)誤信息為無權(quán)限創(chuàng)建目錄。查看工作目錄權(quán)限,當(dāng)前用戶是有權(quán)限的,看了源碼,原來是用的包的問題。首先,在生產(chǎn)環(huán)境下的啟動(dòng)是通過啟動(dòng)的。 前兩天將一個(gè)egg部署到服務(wù)器時(shí),用npm start就是啟動(dòng)不了,錯(cuò)誤信息為無權(quán)限創(chuàng)建log目錄。查看工作目錄權(quán)限,當(dāng)前用戶是有權(quán)限的,看了源碼,原來是用的npm包的問題。這里簡(jiǎn)單記錄下解決過程。 首先,在生...

    waterc 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<