node入門からシリーズ放棄まで(11)優雅なコードで私達のkoa 2プロジェクトを武装します.


コードをお送りします.nodeサービスdemoコード=>koa 2-serverプロジェクトコード;vueフロントエンドdemoコード=>vue-clientプロジェクトコード.ギトが登れないならギtee=>koa 2-serverプロジェクトコードに変えられます.vueフロントエンドdemoコード=>vue-clientプロジェクトコード
本文は参考にします.優雅なコードで私達のkoa 2プロジェクトを武装します.その中の部分を修正して統合しました.
優雅なコードで私達のkoa 2プロジェクトを武装します.
  • ルートの自動ローディング
  • 開発環境と生産環境の区分
  • 統一インターフェースは、フォーマット
  • に戻る.
  • グローバル異常処理ミドル
  • JWTを使用して認証を完了する
  • .
  • nodejs requireパス別名
  • ルートの自動読み込み
    以前は私のルートはいつもマニュアルで登録されていました.
    //app.js
    const Koa = require('koa');
    const app = new Koa(); 
    
    //   
    const index = require('./routes/index');
    const commom = require('./routes/commom'); //     
    
    app.use(index.routes(), index.allowedMethods());
    app.use(commom.routes(), commom.allowedMethods());
    
    長い間ルートを開発してきたので、ファイルの数が多くなりました.このようにアメリカ式を導入すると、煩わしいです.これらのファイルが自動的に導入され、自動的にロードされるようにする方法がありますか?
    この時は使いやすい依存が必要です.
    npm install require-directory --save
    
    ルートディレクトリの下にフォルダレコードを作って、後でいくつかの共通コードはここに預けます.
    //core/init.js
    const requireDirectory = require('require-directory');
    const Router = require('koa-router'); 
    
    class InitManager {
         
        static initCore(app) {
         
            //  app.js  koa     
            InitManager.app = app;
            InitManager.initLoadRouters();
        }
        static initLoadRouters() {
         
            //                     
            // module     ,apiDirectory          (          ),       visit     
            //                
            const apiDirectory = `${
           process.cwd()}/routes`
            const modules = requireDirectory(module, apiDirectory, {
         
                visit: whenLoadModule
            });
            function whenLoadModule(obj) {
         
                if(obj instanceof Router) {
         
                    // FIXME      
    		        const blackList = ['/image'];
    		        const prefix = obj.opts.prefix;
    		        if (!blackList.includes(prefix)) {
         
    		          InitManager.app.use(obj.routes());
    		        }
                }
            }
        }
    }
    module.exports = InitManager;
    
    // app.js
    const Koa = require('koa');
    const app = new Koa();
    
    const InitManager = require('./core/init');
    // ...        
    //       
    InitManager.initCore(app);
    
    コードはすっきりしていますが、機能の実現は大丈夫です.
    開発環境と生産環境の区分
    時には、2つの異なる環境の下で、私達は異なった処理をしなければならなくて、この時に私達は前倒しで全体の局面の中で相応するパラメーターを注ぎ込む必要があります.
    まずプロジェクトのルートディレクトリでconfigフォルダを作成します.
    // config/config.js
    module.exports = {
         
      environment: 'dev'
    }
    //core/init.js initManager        
    static loadConfig() {
         
        const configPath = process.cwd() + '/config/config.js';
        const config = require(configPath);
        global.config = config;
    }
    
    // app.js
    const Koa = require('koa');
    const app = new Koa();
    
    const InitManager = require('./core/init');
    InitManager.loadConfig(); //     ,     ,            
    // ...        
    //       
    InitManager.initCore(app);
    
    //      
    global.config.environment=== 'dev' ? dev : pro;
    
    グローバルグローバルグローバルのグローバル変数から現在の環境を取り込むことができます.
    でもこのように問題があります.あなたが生産環境を配置する時、マニュアルでconfig.jsのenvironment配置を修正します.
    統一インターフェースを返します.
    統一した戻りフォーマットは、先端の処理効率を向上させ、コンポーネント化が開発された今日においても、統一した戻りフォーマットは、先端をより良いパッケージにすることができます.もし一つのプロジェクトの中に同じ返送フォーマットがないなら、このプロジェクトのコードの品質は大体どこに行けばいいですか?
    成功と失敗の戻りフォーマットを先に定義します.
    // middleware/response/response.js
    /**
     * response
     * @param ctx
     * @param data   
     * @param code     || [   ,     ]
     * @param message     
     */
    exports.response = (ctx, data, code, message) => {
         
      if (typeof code == 'object') {
         
        message = code[1];
        code = code[0];
      }
      ctx.body = {
         
        code,
        data,
        message
      };
    };
    
    /**
     * response   
     * @param ctx
     * @param data   
     * @param code     || [   ,     ]
     * @param message     
     */
    exports.success = (ctx, data, code = 1, message = '    ') => {
         
      if (typeof code === 'string') {
         
        message = code;
      }
      this.response(ctx, data, code, message);
    };
    
    /**
     * response   
     * @param ctx
     * @param code     || [   ,     ]
     * @param message     
     */
    exports.error = (ctx, code = 0, data = '', message = '    ') => {
         
      if (typeof code === 'object') {
         
        message = code[1];
        code = code[0];
      }
      ctx.errorLog(ctx, message, 0); //       
      this.response(ctx, data, code, message);
    };
    
    //     
    // middleware/response/index.js
    const {
          success, error } = require('./response');
    
    module.exports = async (ctx, next) => {
         
      ctx.success = success.bind(null, ctx);
      ctx.error = error.bind(null, ctx);
      await next();
    };
    
    // app.js
    // ...      
    const response = require('./middleware/response');
    app.use(response); //       
    // ...
    
    このように帰る時はそのまま使えばいいです.フォーマットが統一されていて、見た目が楽です.
    ctx.error([0, '    ']);
    // or
    ctx.success(xxx);
    
    グローバル異常処理ミドル件
    サービス端末アプリの作成中、異常処理は非常に重要な一環であり、各関数の結果は私たちが望むものではないからです.文法の誤りであろうと、やはり業務の論理の上の誤りであろうと、すべて異常を投げ出させなければならなくて、問題を最も直観的な方式で暴露させて、直接無視するのではありません.コードのスタイルについては、「コード大全」でも強調されていますが、一つの関数が異常に遭遇した場合、一番いい方法は直接return false/nullではなく、異常を直接に投げ出すことです.異常を直接先端に投げてしまうと、このバックエンドの本当の料理を感じさせます.必ず包装します.
    設計異常処理中間件
    // middleware/errorHandler.js
    //                  
    const catchError = async (ctx, next) => {
         
      try {
         
        await next();
      } catch (error) {
         
        // console.log(error);
        if (error.errno) {
         
          // FIXME sql    
          ctx.error([0, 'sql    '], error.sqlMessage);
        } else if (error.code) {
         
          ctx.error([error.code, error.msg]);
        } else {
         
          //        ,      
          ctx.errorLog(ctx, error, 'we made a mistake'); //       
          ctx.error([-1, '     ']);
        }
      }
    };
    
    module.exports = catchError;
    
    
    入り口の書類にこの中間部品を使います.
    // app.js
    //         
    const errorHandler = require('./middleware/errorHandler');
    app.use(errorHandler);
    
    次に、HttpExceptionを例に特定のタイプの異常を生成します.
    // core/http-exception.js
    class HttpException extends Error {
         
      constructor(msg = '     ', code = 400) {
         
        super();
        this.code = code;
        this.msg = msg;
      }
    }
    
    class ParamError extends HttpException {
         
      constructor(msg) {
         
        super();
        this.code = 400;
        this.msg = msg || '    ';
      }
    }
    
    class NotFound extends HttpException {
         
      constructor(msg) {
         
        super();
        this.msg = msg || '     ';
        this.code = 404;
      }
    }
    
    class AuthFailed extends HttpException {
         
      constructor(msg) {
         
        super();
        this.msg = msg || '    ';
        this.code = 404;
      }
    }
    
    class Forbidden extends HttpException {
         
      constructor(msg) {
         
        super();
        this.msg = msg || '    ';
        this.code = 404;
      }
    }
    
    module.exports = {
         
      HttpException,
      ParamError,
      NotFound,
      AuthFailed,
      Forbidden
    };
    
    このような頻繁に呼び出されるエラー処理のコードは、毎回導入する必要がないグローバルに置く必要があります.
    現在のinit.jsの中ではこうです.
    const requireDirectory = require('require-directory');
    const Router = require('koa-router');
    
    class InitManager {
         
      static initCore(app) {
         
        //  app.js  koa     
        InitManager.app = app;
        InitManager.initLoadRouters();
        InitManager.loadHttpException(); //      Exception
      }
    
      static initLoadRouters() {
         
        //                     
        //         
        const apiDirectory = `${
           process.cwd()}/routes`;
        const modules = requireDirectory(module, apiDirectory, {
         
          visit: whenLoadModule
        });
        function whenLoadModule(obj) {
         
          if (obj instanceof Router) {
         
            // FIXME      
            const blackList = ['/image'];
            const prefix = obj.opts.prefix;
            if (!blackList.includes(prefix)) {
         
              InitManager.app.use(obj.routes());
            }
          }
        }
      }
    
      static loadConfig(path = '') {
         
        const configPath = path || process.cwd() + '/config/config.js';
        const config = require(configPath);
        global.config = config;
      }
    
      static loadHttpException() {
         
        const errors = require('./http-exception');
        global.err = errors;
      }
    }
    
    module.exports = InitManager;
    
    これで全体的に使うことができます.
    //    
    if (xxx) throw new global.err.ParamError(xxx);
    
    でもthrowの方法でしか投げられないようです.また、クラスなので、newを実例化して、後から見て最適化してもいいですか?
    JWTを使って認証を完了します.
    これは前シリーズ(7)で専門的に書きましたが、ここでは書きません.本稿で参考にした文章の中で紹介したようにもできます.しかし、リフレッシュtokenの使用が足りないので、空きがあります.
    nodejs requireパスの別名
    開発の過程で、プロジェクトのディレクトリがますます複雑になると、パッケージの参照経路もますます面倒になります.以前からこのようなインポートパスがありました.
    const Favor = require('../../../models/favor');
    
    これより長い導入方法もあります.コード潔癖症のプログラマーとして見ていて、とても不快です.このような問題は絶対パスprocess.cwd()によって解決できますが、カタログがある程度深いと、導入されたコードも非常に煩雑です.もっといい解決方法がありますか?
    module-aliasを使って経路を別名でいいです.
    npm install module-alias --save
    //package.json      
      "_moduleAliases": {
        "@root": ".", //    
        "@models": "app/models",
      },
    
    ポイント:このライブラリをap.jsに導入する:
    //     
    require('module-alias/register');
    
    コードを導入するとこうなります.
    const Favor = require('@models/favor');
    
    このようにエイリアスを使ったら、vscodeの中でF 12は関数の定義位置が見つけられなくなります.ちょっと足りません.
    下一篇:nodeは入門からシリーズの(10)図形の検証の機能を放棄しますまで下一篇:未完は続きます!