1. 程式人生 > >NodeJS_08_art-template子模板與模板繼承_MongoBooster_express-session_三大類中介軟體_全域性錯誤處理

NodeJS_08_art-template子模板與模板繼承_MongoBooster_express-session_三大類中介軟體_全域性錯誤處理

NodeJS七天課程學習筆記_第8天 Blog綜合案例

Blog 綜合案例 (包含註冊登入、修改密碼登出釋出分頁列表、評論、個人中心上傳頭像等)

課程內容概要:

    1. 介紹art-template中的 子模板模板繼承

    2. 介紹表單同步提交與非同步提交的區別

    3. 介紹了視覺化管理工具MongoBooster

    4. 介紹了blueimp/javascript-MD5的配置和使用

    5. 介紹express-session的配置與使用

    6. 註冊、登入 與 退出 功能的實現

    7. 介紹 Express 中介軟體 原理

    8. express中的 三大類 中介軟體

    9. express中的 全域性統一錯誤處理

注意: Node中有許多第3方模板引擎,不只有art-template,還有:

ejs (e代表effective高效之意,從json中生成html的一種魔法) 、

jade(因版權問題,後改名pug哈巴狗)、

handlebars(號稱logic-less templateheima的manmanmai專案用到)、

nunjucks(是Mozilla開發的一個純JavaScript編寫的模板引擎)

首先講art-template中的子模板(include) 以及 模板繼承(extend)語法

官方文件地址 aui.github.io/art-template/zh-cn/docs/syntax.html



第1步, 新建下面4個檔案 作為將來 被包含的子模板

公共的頂部public_top.html、

公共的底部public_footer.html、

公共的左側邊欄public_left.html、

公共的右廣告欄public_right.html


第2步,新增 node_51_base_layout.html 作為將來被各個實際頁面繼承(extend)的母板

母板裡面有個完整的骨架,

母板裡包含(include)了公共的頂部、底部、左側邊欄、右廣告欄

母板裡head引入所有頁面要用到的公共的css(如bootstrap)、js(如jquery)

同時,母板裡,

通過block語法,在head標籤中 預留了 實際頁面真正要用到的 title、css、 js空間

通過block語法,在body標籤中 預留了 實際頁面真正要用到的html 空間

node_51_base_layout.html母板完整程式碼如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
    <link rel="icon" href="public/img/beyond.jpg" type="image/x-icon"/>
    <meta charset="UTF-8">
    <meta name="author" content="beyond">
    <meta http-equiv="refresh" content="520">
    <meta name="description" content="未聞花名-免費零基礎教程-beyond">
    <meta name="viewport" content="width=device-width, 
    initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,彙編,日語,英語,泰語,韓語,俄語,粵語,阿語,魔方,樂理,動漫,PR,PS,AI,AE">
    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
        <![endif]-->

    <!-- 公共的樣式 -->
    <style type="text/css">
        body{
            font-size: 100%; 
            /*宣告margin和padding是個好習慣*/  
            margin: 0;  
            padding: 0; 
            background-image: url("public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
        }
    </style>
    <!-- 公共的樣式 -->
    <link rel="stylesheet" type="text/css" href="public/css/beyondbasestylewhite5.css">
    <!-- 綠色按鈕的css效果 -->
    <link rel="stylesheet" type="text/css" href="public/css/beyondbuttongreen.css">        

    <!-- 公共的JS特效 -->
    <script type="text/javascript" src="public/js/nslog.js"></script>
    <!-- jquery -->
    <script type="text/javascript" src="public/js/jquery2.1.4.js"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" href="public/lib/bootstrap/dist/css/bootstrap.css">
    <script type="text/javascript" src="public/lib/bootstrap/dist/js/bootstrap.js"></script>

    <!-- 這個標題 要留一個坑,給後代去實現自己的title -->
    <title>
        {{ block 'block_1_title'}}
            beyond心中の動漫神作
        {{ /block }}
    </title>

    <!-- 這個head中要 要留一個坑,給後代去連結自己的css或js-->
    {{ block 'block_2_head_css_js'}}
    {{ /block }}

    </head>  
    <body>
        <!-- include進來公共的頂部、底部、左側邊欄、右廣告欄 -->
        {{ include './public_top.html' }}
        {{ include './public_left.html' }}
        
        <!-- 這個body最後要 要留一個坑,給後代去實現自己的content-->
        {{ block 'block_3_body_content'}}
                這是母板預設的正文<br/>
        {{ /block }}

        {{ include './public_right.html' }}
        {{ include './public_footer.html' }}

        <!-- 這個body最後要 要留一個坑,給後代去實現自己的js-->
        {{ block 'block_4_body_js'}}
        {{ /block }}
    </body>
</html>


第3步,現在就可以新建首頁node_51_index.html了 ,

該首頁 繼承(extend) 自 base_layout.html母板

node_51_index.html完整程式碼如下:

<!-- 第0步,繼承母板 -->
{{ extend './node_51_base_layout.html' }}

<!-- 第1步,自己的標題 -->
{{ block 'block_1_title'}}
	自己的標題_首頁
{{ /block }}

<!-- 第2步,自己的head中的css或js -->
{{ block 'block_2_head_css_js'}}
	<style type="text/css">
		body{
			background-color: rgba(166,166,166,0.1);
		}
	</style>
	<script type="text/javascript">
		alert('我是index的head中的js')
	</script>
{{ /block }}

<!-- 第3步,自己的正文 -->
{{ block 'block_3_body_content'}}
	自己的正文<br/>
{{ /block }}

<!-- 第4步,自己的正文最後的js程式碼 -->
{{ block 'block_4_body_js'}}
	<script type="text/javascript">
		alert('我是index的body最後的js')
	</script>
{{ /block }}

入口檔案node_51_index.js程式碼如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  


// 匯入框架
var express = require('express')
var path = require('path')
// 建立伺服器物件
var appServer = express()
// 監聽埠,並啟動服務
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('啟動失敗: ' + error)
	}
	NSLog('服務啟動成功')
})
// -----------------------------------

// 靜態資源請求時的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public' 

// 訪問也只能使用 localhost:5267/public/img/beyond.jpg
// 磁碟上的靜態資源目錄
var staticFilePath = './public/'   
// var staticFilePath = 'public' 

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)
// 再開一個靜態資源目錄
appServer.use('/uploads/',express.static(path.join(__dirname,'uploads')))

// -----------------------------------

// 指明:對於 所有後綴為html 的模板檔案 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面這一句引數配置,可有可無
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板檔案放在預設的views目錄下,則可以通過下面程式碼更改設定
// appServer.set('views','其他目錄')

// -----------------------------------
// 使用middleware中介軟體body-parser進行post請求體中資料解析
var bodyParser = require('body-parser')
// 設定解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))        
// 設定解析 application/json
appServer.use(bodyParser.json())

// -----------------------------------
// 自定義路由設計的目的是:
// 1.讓主入口程式的職責更加單一,程式碼更加簡潔
//     1.1 建立服務
//     1.2 做一些服務相關的配置,比如:
//           1.2.1 靜態資源配置
//           1.2.2 模板引擎配置
//           1.2.3 body-parse 解析表單
//           1.2.4 掛載自定義路由
//           1.2.5 監聽埠,啟動服務
// 使用自定義的路由模組 必須使用./
// 注意: 配置模板引擎和body-parser, 一定要在掛載路由之前
var beyondRouter = require('./node_51_router')
appServer.use(beyondRouter)

路由檔案node_51_router.js程式碼如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  
/*
	自定義路由模組的職責是:
		專門處理所有的路由
		根據不同的請求方式和路徑,採取相應的處理方法
*/ 
// express 專門提供了路由的處理方法
var express = require('express')

// ---------------使用formidable解析上傳的圖片--------------------
var formidable = require('formidable')
// var util = require('util')
var path = require('path')
// -----------------------------------

// 1.使用express專門提供的路由器處理路由 
var router = express.Router()

// -----------------------------------
// 時間格式化
// var BeyondDateFormatFunction = require('./BeyondDateFormat')

// ----------------首頁-------------------
router.get('/',function (request,response) {
	response.render('index/node_51_index.html')
})

// 3.在模組檔案最後,匯出router
module.exports = router

通過node_51_index.js入口 載入 node_51_router.js路由之後

啟動伺服器,渲染效果如下:


Blog專案開始 

第1步. 專案初始化

        首先npm init -y ,生成package.json

        然後git init,然後手動新建.gitignore檔案

第2步. npm 安裝 mongoose和express和art-template和express-art-template

第3步. 專案目錄

        public目錄下有img和css和js和lib目錄

        views目錄下放著html模板, 分成了登入註冊模組、文章模組

第4步. 路由設計

路由設計
請求路由方法GET引數POST引數是否需要登入許可權(沒用到)備註
/GET首頁index.html即文章列表
/registerGET註冊頁面register.html
/registerPOSTemail,password,username處理註冊的POST請求
/loginGET登入頁面login.html
/loginPOSTemail,password處理登入POST請求

首先處理的路由是 / , 渲染首頁node_52_index.html

由於資料庫內暫時還沒有資料,所以首頁只用幾個假的資料先填充,以保證樣式正常

首頁的渲染效果如下:


首頁node_52_index.html程式碼(暫未使用模板引擎渲染)如下:

<!-- 第0步,繼承母板 -->
{{ extend './node_52_base_layout.html' }}

<!-- 第1步,自己的標題 -->
{{ block 'block_1_title'}}
	未聞花名_多使用者部落格系統_首頁
{{ /block }}

<!-- 第2步,自己的head中的css或js -->
{{ block 'block_2_head_css_js'}}
	<style type="text/css">
		body{
			background-color: rgba(166,166,166,0.1);
		}
	</style>
	<script type="text/javascript">
		// alert('我是index的head中的js')
	</script>
{{ /block }}

<!-- ||||||||||||||||||||||||||||||||| -->
<!-- 第3步,自己的正文 -->
{{ block 'block_3_body_content'}}
	
	
<section class="container">
  <ul class="media-list">
    <li class="media">
      <div class="media-left">
        <a href="#">
            <img width="40" height="40" class="media-object" src="public/img/beyond.jpg" alt="...">
          </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading"><a href="/topics/123">未聞花名</a></h4>
        <p>面碼 發起了話題 • 1314 人關注 • 32 個回覆 • 1992 次瀏覽 • 2006-06-07 22:20</p>
      </div>
    </li>
    <li class="media">
      <div class="media-left">
        <a href="#">
            <img width="40" height="40" class="media-object" src="public/img/beyond.jpg" alt="...">
          </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading"><a href="/topics/123">龍與虎</a></h4>
        <p>逢阪大河 發起了話題 • 520 人關注 • 5 個回覆 • 871 次瀏覽 • 2008-05-20 13:14</p>
      </div>
    </li>
    <li class="media">
      <div class="media-left">
        <a href="#">
            <img width="40" height="40" class="media-object" src="public/img/beyond.jpg" alt="...">
          </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading"><a href="/topics/123">輕音少女</a></h4>
        <p>平澤唯 發起了話題 • 67 人關注 • 1 個回覆 • 244 次瀏覽 • 2010-11-11 17:20</p>
      </div>
    </li>
    <li class="media">
      <div class="media-left">
        <a href="#">
            <img width="40" height="40" class="media-object" src="public/img/beyond.jpg" alt="...">
          </a>
      </div>
      <div class="media-body">
        <h4 class="media-heading"><a href="/topics/123">這個殺手不太冷</a></h4>
        <p>mathilda 發起了話題 • 5 人關注 • 0 個回覆 • 133 次瀏覽 • 2011-06-18 10:36</p>
      </div>
    </li>
  </ul>
  <nav aria-label="Page navigation" style="text-align:center;">
    <ul class="pagination">
      <li>
        <a href="#" aria-label="Previous">
        <span aria-hidden="true">«</span>
      </a>
      </li>
      <li class="active"><a href="#">1</a></li>
      <li><a href="#">2</a></li>
      <li><a href="#">3</a></li>
      <li><a href="#">4</a></li>
      <li><a href="#">5</a></li>
      <li>
        <a href="#" aria-label="Next">
        <span aria-hidden="true">»</span>
      </a>
      </li>
    </ul>
  </nav>
</section>

{{ /block }}
<!-- ||||||||||||||||||||||||||||||||| -->



<!-- 第4步,自己的正文最後的js程式碼 -->
{{ block 'block_4_body_js'}}
	<script type="text/javascript">
		// alert('我是index的body最後的js')
	</script>
{{ /block }}

注意: 首頁node_52_index.html 是 繼承(extend)自 母板 node_52_base_layout.html

母板node_52_base_layout.html程式碼如下:

<!DOCTPYE html>  
<html lang="zh">  
<head>  
    <link rel="icon" href="public/img/beyond.jpg" type="image/x-icon"/>
    <meta charset="UTF-8">
    <meta name="author" content="beyond">
    <meta http-equiv="refresh" content="520">
    <meta name="description" content="未聞花名-免費零基礎教程-beyond">
    <meta name="viewport" content="width=device-width, 
    initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta name="keywords" content="HTML,CSS,JAVASCRIPT,JQUERY,XML,JSON,C,C++,C#,OC,PHP,JAVA,JSP,PYTHON,RUBY,PERL,LUA,SQL,LINUX,SHELL,彙編,日語,英語,泰語,韓語,俄語,粵語,阿語,魔方,樂理,動漫,PR,PS,AI,AE">
    <!--[if lt IE 9]>
        <script src="//apps.bdimg.com/libs/html5shiv/3.7/html5shiv.min.js"></script>
        <script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/1.10.2/jquery.js">
        </script>
        <![endif]-->

    <!-- 公共的樣式 -->
    <style type="text/css">
        body{
            font-size: 100%; 
            /*宣告margin和padding是個好習慣*/  
            margin: 0;  
            padding: 0; 
            background-image: url("public/img/sakura4.png");  
            background-repeat: no-repeat;  
            background-position: center center;  
        }
    </style>
    <!-- 公共的樣式 -->
    <link rel="stylesheet" type="text/css" href="public/css/beyondbasestylewhite5.css">
    <!-- 綠色按鈕的css效果 -->
    <link rel="stylesheet" type="text/css" href="public/css/beyondbuttongreen.css">        

    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" href="public/lib/bootstrap/node_52_v337_bootstrap.css">
    <!-- 公共的JS特效 -->
    <script type="text/javascript" src="public/js/nslog.js"></script>
    

    <!-- 這個標題 要留一個坑,給後代去實現自己的title -->
    <title>
        {{ block 'block_1_title'}}
            beyond心中の動漫神作
        {{ /block }}
    </title>

    <!-- 這個head中要 要留一個坑,給後代去連結自己的css或js-->
    {{ block 'block_2_head_css_js'}}
    {{ /block }}

    </head>  
    <body>
        <!-- include進來公共的頂部、底部、左側邊欄、右廣告欄 -->
        {{ include './node_52_public_top.html' }}
        
        
        <!-- 這個body最後要 要留一個坑,給後代去實現自己的content-->
        {{ block 'block_3_body_content'}}
                這是母板預設的正文<br/>
        {{ /block }}


        <!-- jquery -->
        <script type="text/javascript" src="public/js/jquery2.1.4.js"></script>
    
        <script type="text/javascript" src="public/lib/bootstrap/node_52_v337_bootstrap.js"></script>


        {{ include './node_52_public_footer.html' }}

        <!-- 這個body最後要 要留一個坑,給後代去實現自己的js-->
        {{ block 'block_4_body_js'}}
        {{ /block }}



    </body>
</html>

注意: 

母板node_52_base_layout.html中用到的子模板node_52_public_top.html 以及

子模板node_52_public_footer.html程式碼分別如下:

子模板node_52_public_top.html程式碼如下: (一會兒寫了登入註冊後,再完善)

<nav class="navbar navbar-default">
  <div class="container">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="/">
        <img width="90px" src="public/img/vwhm2.png" alt="">
      </a>
    </div>
    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <!-- <ul class="nav navbar-nav">
          <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
          <li><a href="#">Link</a></li>
          <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
            <ul class="dropdown-menu">
              <li><a href="#">Action</a></li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li role="separator" class="divider"></li>
              <li><a href="#">Separated link</a></li>
              <li role="separator" class="divider"></li>
              <li><a href="#">One more separated link</a></li>
            </ul>
          </li>
        </ul> -->
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
      </form>
      <ul class="nav navbar-nav navbar-right">
        {{ if user }}
        <a class="btn btn-default navbar-btn" href="/topics/new">發起</a>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img width="20" height="20" src="public/img/beyond.jpg" alt=""> <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li class="dropdown-current-user">
              當前登入使用者: {{ 一會寫 }}
            </li>
            <li role="separator" class="divider"></li>
            <li><a href="#">個人主頁</a></li>
            <li><a href="/settings/profile">設定</a></li>
            <li><a href="/logout">退出</a></li>
          </ul>
        </li>
        {{ else }}
        <a class="btn btn-primary navbar-btn" href="/login">登入</a>
        <a class="btn btn-success navbar-btn" href="/register">註冊</a>
        {{ /if }}
      </ul>
    </div>
    <!-- /.navbar-collapse -->
  </div>
  <!-- /.container-fluid -->
</nav>

子模板node_52_public_footer.html程式碼如下:

<footer id="copyright">
	<p style="font-size:14px;text-align:center;font-style:italic;">  
		Copyright © <a id="author">2018</a> Powered by <a id="author">beyond</a>  
	</p>        
</footer>

目前為止,首頁,效果如下:


接下來,點選首頁->右上角按鈕->彈出下拉選單->單擊註冊按鈕

註冊頁面效果如下:


開始渲染node_52_register.html註冊頁面: (包括使用ajax傳送非同步請求(POST註冊)):

程式碼如下:

<!-- 第0步,繼承母板 -->
{{ extend './node_52_base_layout.html' }}

<!-- 第1步,自己的標題 -->
{{ block 'block_1_title'}}
	未聞花名_多使用者部落格系統_註冊
{{ /block }}

<!-- 第2步,自己的head中的css或js -->
{{ block 'block_2_head_css_js'}}
	<link rel="stylesheet" type="text/css" href="public/css/login.css">
	<script type="text/javascript">
		// alert('我是index的head中的js')
	</script>
{{ /block }}

<!-- ||||||||||||||||||||||||||||||||| -->
<!-- 第3步,自己的正文 -->
{{ block 'block_3_body_content'}}
	
<div class="main">
    <div class="header">
      <a href="/">
        <img src="/public/img/vwhm2.png" alt="" style="border:1px solid rgba(191,191,191,0.2);">
      </a>
      <p></p>
    </div>
    <!-- 
      表單具有預設的提交行為,預設是同步的,同步表單提交,瀏覽器會鎖死(轉圈兒)等待服務端的響應結果。
      表單的同步提交之後,無論服務端響應的是什麼,都會直接把響應的結果覆蓋掉當前頁面。

      注意: 同步提交返回的結果 是直接覆蓋掉 當前頁面的內容

      後來有人想到了非同步提交的辦法,來解決這個問題。
     -->
    <form id="id_form_register" method="post" action="/register">
      <div class="form-group">
        <label for="email">郵箱</label>
        <input type="email" class="form-control" id="email" name="email" placeholder="Email" autofocus>
      </div>
      <div class="form-group">
        <label for="username">暱稱</label>
        <input type="text" class="form-control" id="username" name="username" placeholder="Username">
      </div>
      <div class="form-group">
        <label for="password">密碼</label>
        <input type="password" class="form-control" id="password" name="password" placeholder="Password">
      </div>
      <button type="submit" class="btn btn-success btn-block">註冊</button>
    </form>
    <div class="message">
      <p>已有賬號? <a href="/login">點選登入</a>.</p>
    </div>
    <p></p>
  </div>

{{ /block }}
<!-- ||||||||||||||||||||||||||||||||| -->



<!-- 第4步,自己的正文最後的js程式碼 -->
{{ block 'block_4_body_js'}}
	<!-- 使用blueimp-md5加密 (算了,只在服務端md5加密了)-->
	<script type="text/javascript" src="public/js/md5.min.js"></script>
	<script type="text/javascript">
		// alert('我是index的body最後的js')
		$('#id_form_register').on('submit',function (event) {
			// 阻止預設的事件行為
			event.preventDefault()
			// 獲取表單資料 (使用jQuery中表單物件的serialize方法)
			var formData = $(this).serialize()
			// 傳送ajax請求之前應該要先做客戶端表單驗證
			$.ajax({
				url: '/register',
				type: 'post',
				data: formData,
				dataType: 'json',
				success: function (responseObj) {
					/*
					err為0, 註冊成功,客戶端重定向(因為伺服器重定向對 非同步請求 無效)
					err為1, email已被註冊過
					err為2, username已被佔用
					err為500, 伺服器崩潰
					*/ 
					var err = responseObj.err
					switch(err){
						case 0:
							window.location.href = '/'
							break
						case 1:
							window.alert('email已註冊')
							break
						case 2:
							window.alert('username已存在')
							break
						case 3:
							window.alert('email已註冊或username已存在')
							break
						case 500:
							window.alert('伺服器崩潰' + responseObj.msg)
							break
						default:
							window.alert('未知異常')

					}
				}
			})

		})
	</script>
{{ /block }}

接下來編寫服務端的程式碼, 以便處理ajax提交post過來的註冊請求

這兒我們使用mongodb + mongoose中介軟體

第1步, 開啟命令列,執行mongod 啟動mongodb資料庫服務

第2步,新建node_52_userdao.js,  建立User資料模型Schema

(注意: 後面我們還會建立articledao.js用來操作文章入庫的CRUD)

(注意: 後面我們還會建立commentdao.js用來操作評論入庫的CRUD)

node_52_userdao.js程式碼如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  

// ----------------初始化------------------- 
var mongoose = require('mongoose')
// 連線資料庫 db2,預設埠是: 27017
mongoose.connect('mongodb://localhost/db2')
var Schema = mongoose.Schema
// 設計使用者表結構 
var userSchema = new Schema({
	email: {
		type: String,
		required: true
	},
	username: {
		type: String,
		required: true
	},
	password: {
		type: String,
		required: true
	},
	pubTime: {
		type: String,
		required: true,
		/* 
			type: Date,
			default: Date.now
			預設值:  只寫一個函式名,不加括號就不會立即呼叫,
			因為一旦加括號,就會立即呼叫,會立刻執行
		*/
		default: ''
	},
	usersex: {
		type: Number,
		required: false,
		default: 0
	},
	userage: {
		type: Number,
		// enum: [8,9,10,11,12,13,14,15,16],
		default: 13
	},
	userimg: {
		// 使用者頭像url
		type: String,
		required: false,
		default: 'beyond.jpg'
	},
	userdescription: {
		type: String,
		required: false,
		default: 'vwhm.net'
	},
	userstatus: {
		// 0無限制,1限制評論,2限制釋出,3限制登入
		type: Number,
		enum: [0,1,2,3],
		default: 0
	}
})


// 核心程式碼: 直接匯出 模型建構函式
// 引數1: User 首字母必須大寫,且必須是單數; 
// 這樣就能自動生成users表(集合)
module.exports = mongoose.model('User',userSchema)

第3步,安裝和配置body-parser中介軟體,自動化處理表單請求

第4步,儲存入庫,並將操作結果的json資料 回寫瀏覽器

這個儲存之前,要先查詢 email 或者 username是否已經存在,

使用到了mongoose官方文件 中的 or 語法,mongoosejs.com/docs/api.html#query_Query-or


也可以參照mongodb官方文件 中的 or 條件語法


在node_52_router.js中,處理post過來的register請求時,

先判斷資料庫中是否已經存在email和username

如果查詢錯誤,那麼給瀏覽器報錯500,Server Error
如果email已註冊,那麼給瀏覽器報錯err = 1
如果username已存在,那麼給瀏覽器報錯err = 2

如果使用or查詢,為了少寫一個介面,那麼給瀏覽器報錯err = 3,email已註冊或username已存在

如果查詢結果為null,那麼執行註冊save操作,

如果save結果出錯,那麼給瀏覽器報錯500

如果save成功,那麼給瀏覽器返回{"err":0,"msg":"註冊成功"}

瀏覽器就會收到非同步請求返回的結果,進行客戶端跳轉了

在這期間, 插句題外話,推薦了一個客戶端軟體 MongoBooster 對MongoDB資料庫進行視覺化管理


安裝後, 通過url  localhost:27017 進行連線mongodb資料庫

然後就可以選擇db2資料庫,執行查詢語句了...


在這期間,還插了一句題外話,使用md5 中介軟體

客戶端直接引入,然後使用

<script src="public/js/md5.min.js"></script>

就可以使用了

var hash = md5("password");

服務端先 npm install blueimp-md5 ,然後使用:

var hash = md5("password");

最後,處理註冊請求的node_52_router.js程式碼如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  
/*
	自定義路由模組的職責是:
		專門處理所有的路由
		根據不同的請求方式和路徑,採取相應的處理方法
*/ 
// express 專門提供了路由的處理方法
var express = require('express')
// blueimp-md5對password加密再存入資料庫
var md5 = require('./md5')
// ---------------使用formidable解析上傳的圖片--------------------
var formidable = require('formidable')
// var util = require('util')
var path = require('path')
// -----------------------------------

// 1.使用express專門提供的路由器處理路由 
var router = express.Router()

// ----------------引入dao模組-------------------
// 先對dao初始化
var UserDaoFunction = require('./node_52_userdao')
// 時間格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')

// ----------------首頁-------------------
router.get('/',function (request,response) {
	response.render('index/node_52_index.html')
})

// ----------------註冊頁面-------------------
router.get('/register',function (request,response) {
	response.render('index/node_52_register.html')
})

// ----------------進行註冊-------------------
router.post('/register',function (request,response) {
	/*
	先判斷資料庫中是否已經存在email和username
	如果查詢錯誤,報錯500,Server Error
	如果email已註冊,報錯err = 1
	如果username已存在,報錯err = 2
	如果使用or查詢,為了少寫一個介面,報錯err = 3,email已註冊或username已存在
	*/ 
	// 直接獲取body-parser中post過來的表單
	var bodyObj = request.body
	// 使用blueimp-md5進行加密 (可加兩次)
	bodyObj.password = md5(md5(bodyObj.password))
	// 手動添加當前時間
	bodyObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd hh:mm:ss')

	UserDaoFunction.findOne({
		$or: [
				{
					email: bodyObj.email
				},
				{
					username: bodyObj.username
				}
		]
	})
	.then(function (data) {
		// then方法的引數1是: resolveCallback
		NSLog('data: ' + data)
		if (data === null) {
			// 來到這兒說明 可以進行真正的註冊
			// new 一個物件, 然後執行save方法並生成一個promise,為了避免callback hell 我們把它return, 目的是使用鏈式的then方法
			var promise_2 = new UserDaoFunction(bodyObj).save()
			return promise_2
		}

		// 來到這兒,說明有data 則表示 已存在了
		response.status(200).json({
				err: 3,
				msg: 'email已註冊或username已存在'
		})
		
	},function (error) {
		// then方法的引數2是: rejectCallback
		//  如果查詢失敗,則返回500錯誤
		NSLog('error: ' + error)
		// express 內部 提供了一個json方法,自動把物件轉成json
		response.status(500).json({
			err: 500,
			msg: error
		})
	})
	.then(function (data) {
		// then方法的引數1是: promise_2的resolveCallback
		// 儲存成功
		response.status(200).json({
			err: 0,
			msg: '註冊成功'
		})
	},function (error) {
		// then方法的引數2是: promise_2的rejectCallback
		// 儲存失敗
		response.status(500).json({
			err: 500,
			msg: error
		})
	})


})

// 3.在模組檔案最後,匯出router
module.exports = router

註冊效果執行如下:


開啟MongoBooster,使用command + R重新整理一下, 檢視資料庫如下:


再次強調了一下, 服務端重定向,對於瀏覽器的非同步請求無效!!! 記住就ok

      表單具有預設的提交行為,預設是同步的,表單同步提交,瀏覽器會鎖死(轉圈兒)等待服務端的響應結果。

      表單的同步提交之後,無論服務端響應的是什麼,都會直接把響應的結果覆蓋掉當前頁面。

      因此,以前的開發時,還要實現資料回顯,即在重新渲染頁面時,把前面提交過來的資料 填充到表單元素中

      注意: 同步提交返回的結果 是直接覆蓋掉 當前頁面的內容

      後來有人想到了非同步提交的辦法,來解決這個問題。

如今github仍然使用的是表單同步提交, 就是因為這樣由服務端統一渲染,比較安全,雖然伺服器壓力大一些

補充一下,github 是一個 ruby on rails專案


由於express預設是不支援cookie和session的,

因此, 下面 使用express-session中介軟體,來儲存使用者登入的狀態

express-session 官方文件: npmjs.com/package/express-session

第1步, 安裝

npm install express-session --save

第2步, 配置 (一定要在appServer.use(router)之前)

// ---------express-session中介軟體配置------------------
// express-session 步驟2 
appServer.use(session({
	// 金鑰,為了安全起見
	secret: 'vwhm.net',
	// 
	resave: false,
	// true表示 尚未使用 就進行初始化一個sessionID
	saveUninitialized: true
}))

第3步, 使用request.session.user 即可 設定或讀取 session  

(注意:此狀態下的session 不是持久化的, 只是記憶體裡,重啟伺服器就沒有了)

我們在UserDao儲存註冊使用者的時候,就將save()方法返回的user物件,存入session內

request.session.user = userFromDB

第4步, 在渲染node_52_index.html時, 將session中的user物件渲染過去

如果session有user,那麼 顯示 使用者名稱

如果session沒有user,那麼 顯示 登入和註冊

第5步, 登出的話,只要 置null 並 delete request.session.user即可

效果如下:


node_52_index.js程式碼如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  

// --------匯入框架---------------------------
var express = require('express')
var path = require('path')
// express-session 步驟1
var session = require('express-session')

// --------建立並啟動伺服器--------------------------
var appServer = express()
// 監聽埠,並啟動服務
appServer.listen(5267,function (error) {
	if (error) {
		return NSLog('啟動失敗: ' + error)
	}
	NSLog('服務啟動成功')
})

// --------靜態資源配置---------------------------
// 靜態資源請求時的 staticFileUrlPrefix
var staticFileUrlPrefix = '/public/'
// var staticFileUrlPrefix = '/public' 

// 訪問也只能使用 localhost:5267/public/img/beyond.jpg
// 磁碟上的靜態資源目錄(強烈推薦轉成絕對路徑)
// var staticFilePath = './public/'   
// var staticFilePath = 'public' 
var staticFilePath = path.join(__dirname,'public')

var callbackFunction = express.static(staticFilePath)
appServer.use(staticFileUrlPrefix,callbackFunction)
// 再開一個靜態資源目錄
appServer.use('/uploads/',express.static(path.join(__dirname,'uploads')))

// ---------art-template模板引擎配置-------------------

// 指明:對於 所有後綴為html 的模板檔案 使用模板引擎
var templateFileSuffix = 'html'
appServer.engine(templateFileSuffix,require('express-art-template'))
// 下面這一句引數配置,可有可無
appServer.set('view options',{
	debug: process.env.NODE_ENV !== 'production'
})
// 注意:如果不想把模板檔案放在預設的views目錄下,則可以通過下面程式碼更改設定
// appServer.set('views','其他目錄')

// ---------body-parser中介軟體配置---------------------
// 使用middleware中介軟體body-parser進行post請求體中資料解析
var bodyParser = require('body-parser')
// 設定解析 application/x-www-form-urlencoded
appServer.use(bodyParser.urlencoded({extended: false}))        
// 設定解析 application/json
appServer.use(bodyParser.json())

// ---------express-session中介軟體配置------------------
// express-session 步驟2 
// 該中介軟體 會為request增加一個session的成員,預設型別為物件
// 本例中,session是在記憶體中儲存的,一旦伺服器重啟就不在了
// 在實際生產環境下,需要對session進行持久化
appServer.use(session({
	// 自定義金鑰,為了安全起見
	secret: 'vwhm.net',
	// 
	resave: false,
	// true表示 無論用不用session 都進行初始化一個sessionID
	saveUninitialized: true
}))
// -----------------------------------
// 自定義路由設計的目的是:
// 1.讓主入口程式的職責更加單一,程式碼更加簡潔
//     1.1 建立服務
//     1.2 做一些服務相關的配置,比如:
//           1.2.1 靜態資源配置
//           1.2.2 模板引擎配置
//           1.2.3 body-parse 解析表單
//           1.2.4 掛載自定義路由
//           1.2.5 監聽埠,啟動服務
// 使用自定義的路由模組 必須使用./
// 注意: 配置模板引擎和body-parser, 一定要在掛載路由之前
var beyondRouter = require('./node_52_router')
appServer.use(beyondRouter)

node_52_router.js程式碼如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  
/*
	自定義路由模組的職責是:
		專門處理所有的路由
		根據不同的請求方式和路徑,採取相應的處理方法
*/ 
// express 專門提供了路由的處理方法
var express = require('express')
// blueimp-md5對password加密再存入資料庫
var md5 = require('./md5')
// ---------------使用formidable解析上傳的圖片--------------------
var formidable = require('formidable')
// var util = require('util')
var path = require('path')
// -----------------------------------

// 1.使用express專門提供的路由器處理路由 
var router = express.Router()

// ----------------引入dao模組-------------------
// 先對dao初始化
var UserDaoFunction = require('./node_52_userdao')
// 時間格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')

// ----------------首頁-------------------
router.get('/',function (request,response) {
	response.render('index/node_52_index.html',{
		/*
		在渲染index.html時, 將session中的user物件渲染過去
		如果session有user,那麼 顯示 使用者名稱
		如果session沒有user,那麼 顯示 登入和註冊
		*/ 
		user: request.session.user
	})
})

// ----------------註冊頁面-------------------
router.get('/register',function (request,response) {
	response.render('index/node_52_register.html')
})

// ----------------進行註冊-------------------
router.post('/register',function (request,response) {
	/*
	先判斷資料庫中是否已經存在email和username
	如果查詢錯誤,報錯500,Server Error
	如果email已註冊,報錯err = 1
	如果username已存在,報錯err = 2
	如果使用or查詢,為了少寫一個介面,報錯err = 3,email已註冊或username已存在
	*/ 
	// 直接獲取body-parser中post過來的表單
	var bodyObj = request.body
	// 使用blueimp-md5進行加密 (可加兩次)
	bodyObj.password = md5(md5(bodyObj.password))
	// 手動添加當前時間
	bodyObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd hh:mm:ss')

	UserDaoFunction.findOne({
		$or: [
				{
					email: bodyObj.email
				},
				{
					username: bodyObj.username
				}
		]
	})
	.then(function (data) {
		// then方法的引數1是: resolveCallback
		NSLog('data: ' + data)
		if (data === null) {
			// 來到這兒說明 可以進行真正的註冊
			// new 一個物件, 然後執行save方法並生成一個promise,為了避免callback hell 我們把它return, 目的是使用鏈式的then方法
			var promise_2 = new UserDaoFunction(bodyObj).save()
			return promise_2
		}

		// 來到這兒,說明有data 則表示 已存在了
		response.status(200).json({
				err: 3,
				msg: 'email已註冊或username已存在'
		})
		
	},function (error) {
		// then方法的引數2是: rejectCallback
		//  如果查詢失敗,則返回500錯誤
		NSLog('error: ' + error)
		// express 內部 提供了一個json方法,自動把物件轉成json
		response.status(500).json({
			err: 500,
			msg: error
		})
	})
	.then(function (userFromDB) {
		// then方法的引數1是: promise_2的resolveCallback
		// 儲存成功的話, 記錄到session中
		request.session.user = userFromDB

		response.status(200).json({
			err: 0,
			msg: '註冊成功'
		})
	},function (error) {
		// then方法的引數2是: promise_2的rejectCallback
		// 儲存失敗
		response.status(500).json({
			err: 500,
			msg: error
		})
	})


})
// ----------------登出請求-------------------
router.get('/logout',function (request,response) {
	// 清除session 並 重定向到首頁
	request.session.user = null
	delete request.session.user
	response.redirect('/')
})

// 3.在模組檔案最後,匯出router
module.exports = router

最後再把登入功能實現一下 (後面的上傳頭像、釋出、評論、找回密碼等等等以後再寫)

node_52_login.html程式碼如下:

<!-- 第0步,繼承母板 -->
{{ extend './node_52_base_layout.html' }}

<!-- 第1步,自己的標題 -->
{{ block 'block_1_title'}}
	未聞花名_多使用者部落格系統_註冊
{{ /block }}

<!-- 第2步,自己的head中的css或js -->
{{ block 'block_2_head_css_js'}}
	<link rel="stylesheet" type="text/css" href="public/css/login.css">
	<script type="text/javascript">
		// alert('我是index的head中的js')
	</script>
{{ /block }}

<!-- ||||||||||||||||||||||||||||||||| -->
<!-- 第3步,自己的正文 -->
{{ block 'block_3_body_content'}}
	
<div class="main">
    <div class="header">
      <a href="/">
        <img src="/public/img/vwhm2.png" alt="" style="border:1px solid rgba(191,191,191,0.2);">
      </a>
      <h1>使用者登入</h1>
    </div>
    <form id="id_form_login">
      <div class="form-group">
        <label for="">郵箱</label>
        <input type="email" class="form-control" id="" name="email" placeholder="Email" autofocus>
      </div>
      <div class="form-group">
        <label for="">密碼</label>
        <a class="pull-right" href="">忘記密碼?</a>
        <input type="password" class="form-control" id="" name="password" placeholder="Password">
      </div>
      <div class="checkbox">
        <label>
          <input type="checkbox">記住我
        </label>
      </div>
      <button type="submit" class="btn btn-success btn-block">登入</button>
    </form>
    <div class="message">
      <p>沒有賬號? <a href="/register">點選建立</a>.</p>
    </div>
  </div>

{{ /block }}
<!-- ||||||||||||||||||||||||||||||||| -->



<!-- 第4步,自己的正文最後的js程式碼 -->
{{ block 'block_4_body_js'}}
	<!-- 使用blueimp-md5加密 (算了,只在服務端md5加密了)-->
	<script type="text/javascript" src="public/js/md5.min.js"></script>
	<script type="text/javascript">
		// alert('我是index的body最後的js')
		$('#id_form_login').on('submit',function (event) {
			// 阻止預設的事件行為
			event.preventDefault()
			// 獲取表單資料 (使用jQuery中表單物件的serialize方法)
			var formData = $(this).serialize()
			// 傳送ajax請求之前應該要先做客戶端表單驗證
			$.ajax({
				url: '/login',
				type: 'post',
				data: formData,
				dataType: 'json',
				success: function (responseObj) {
					/*
					err為0, 登入成功,客戶端重定向(因為伺服器重定向對 非同步請求 無效)
					err為1, 郵箱或密碼錯誤
					err為500, 伺服器崩潰
					*/ 
					var err = responseObj.err
					switch(err){
						case 0:
							window.location.href = '/'
							break
						case 1:
							window.alert('郵箱或密碼錯誤')
							break
						case 500:
							window.alert('伺服器崩潰' + responseObj.msg)
							break
						default:
							window.alert('未知異常')

					}
				}
			})

		})
	</script>
{{ /block }}

包含了登入處理請求的node_52_router.js完整程式碼如下:

function NSLog(loli) {console.log(loli);return 'Copyright © 2018 Powered by beyond';};  
/*
	自定義路由模組的職責是:
		專門處理所有的路由
		根據不同的請求方式和路徑,採取相應的處理方法
*/ 
// express 專門提供了路由的處理方法
var express = require('express')
// blueimp-md5對password加密再存入資料庫
var md5 = require('./md5')
// ---------------使用formidable解析上傳的圖片--------------------
var formidable = require('formidable')
// var util = require('util')
var path = require('path')
// -----------------------------------

// 1.使用express專門提供的路由器處理路由 
var router = express.Router()

// ----------------引入dao模組-------------------
// 先對dao初始化
var UserDaoFunction = require('./node_52_userdao')
// 時間格式化
var BeyondDateFormatFunction = require('./BeyondDateFormat')

// ----------------首頁-------------------
router.get('/',function (request,response) {
	response.render('index/node_52_index.html',{
		/*
		在渲染index.html時, 將session中的user物件渲染過去
		如果session有user,那麼 顯示 使用者名稱
		如果session沒有user,那麼 顯示 登入和註冊
		*/ 
		user: request.session.user
	})
})

// ----------------註冊頁面-------------------
router.get('/register',function (request,response) {
	response.render('index/node_52_register.html')
})

// ----------------進行註冊-------------------
router.post('/register',function (request,response) {
	/*
	先判斷資料庫中是否已經存在email和username
	如果查詢錯誤,報錯500,Server Error
	如果email已註冊,報錯err = 1
	如果username已存在,報錯err = 2
	如果使用or查詢,為了少寫一個介面,報錯err = 3,email已註冊或username已存在
	*/ 
	// 直接獲取body-parser中post過來的表單
	var bodyObj = request.body
	// 使用blueimp-md5進行加密 (可加兩次)
	bodyObj.password = md5(md5(bodyObj.password))
	// 手動添加當前時間
	bodyObj.pubTime = BeyondDateFormatFunction(new Date(),'yyyy-MM-dd hh:mm:ss')

	UserDaoFunction.findOne({
		$or: [
				{
					email: bodyObj.email
				},
				{
					username: bodyObj.username
				}
		]
	})
	.then(function (data) {
		// then方法的引數1是: resolveCallback
		NSLog('data: ' + data)
		if (data === null) {
			// 來到這兒說明 可以進行真正的註冊
			// new 一個物件, 然後執行save方法並生成一個promise,為了避免callback hell 我們把它return, 目的是使用鏈式的then方法
			var promise_2 = new UserDaoFunction(bodyObj).save()
			return promise_2
		}

		// 來到這兒,說明有data 則表示 已存在了
		response.status(200).json({
				err: 3,
				msg: 'email已註冊或username已存在'
		})
		
	},function (error) {
		// then方法的引數2是: rejectCallback
		//  如果查詢失敗,則返回500錯誤
		NSLog('error: ' + error)
		// express 內部 提供了一個json方法,自動把物件轉成json
		response.status(500).json({
			err: 500,
			msg: error
		})
	})
	.then(function (userFromDB) {
		// then方法的引數1是: promise_2的resolveCallback
		// 儲存成功的話, 記錄到session中
		request.session.user = userFromDB

		response.status(200).json({
			err: 0,
			msg: '註冊成功'
		})
	},function (error) {
		// then方法的引數2是: promise_2的rejectCallback
		// 儲存失敗
		response.status(500).json({
			err: 500,
			msg: error
		})
	})
})

// ----------------登出請求-------------------
router.get('/logout',function (request,response) {
	// 清除session 並 重定向到首頁
	request.session.user = null
	delete request.session.user
	response.redirect('/')
})

// ----------------登入介面-------------------
router.get('/login',function (request,response) {
	response.render('index/node_52_login.html')
})

// ----------------進行登入-------------------
router.post('/login',function (request,response) {
	// 1. 獲取表單,對密碼二次加密
	// 直接獲取body-parser中post過來的表單
	var bodyObj = request.body
	// 使用blueimp-md5進行加密 (可加兩次)
	bodyObj.password = md5(md5(bodyObj.password))
	// 2. 使用UserDao查詢 
	UserDaoFunction.findOne({
		email: bodyObj.email,
		password: bodyObj.password
	})
	.then(function (userFromDB) {
		// 如果 userFromDB 為 null,表示 登入失敗
		if (userFromDB === null) {
			return response.status(200).json({
				err: 1,
				msg: '郵箱或密碼錯誤'
			})
		}
		// 來到這兒說明登入成功,記錄session
		request.session.user = userFromDB
		response.status(200).json({
			err: 0,
			msg: '登入成功'
		})
	},function (error) {
		// then方法的引數2是: rejectCallback
		//  如果查詢失敗,則返回500錯誤
		NSLog('error: ' + error)
		// express 內部 提供了一個json方法,自動把物件轉成json
		response.status(500).json({
			err: 500,
			msg: error
		})
	})
})









// 3.在模組檔案最後,匯出router
module.exports = router

最終效果如下: ((後面的上傳頭像、使用xheditor釋出、評論、找回密碼等等等以後再寫))


NodeJS七天課程學習筆記_第8天 中介軟體_全域性錯誤處理

推薦了chrome外掛: EditThisCookie

推薦了模擬各種post和get等請求的工具: PostMan

一張圖說明中介軟體的原理


中介軟體: 實質上是一種包裝方法

中介軟體分為幾種:

     1. 不關心任何請求路徑的中介軟體,如use方法

                appServer.use( function(request,response,next ){

                                NSLog('請求被攔截下來了')

                                // 請求又被放行了

                                next()

                        }

                )

        意思是任何請求,都會進入這個中介軟體

        任何請求都會被這個use方法攔截下來, 後面的中介軟體就無法再獲取到該請求了

        除非在use方法最後一行, 呼叫next() ,放行該請求

     2. 只關心 以/public開頭的中介軟體, 如 /public/img/beyond.jpg或者/public/js/jquery.js

        像這樣的只有是以/public開頭的請求,才會被攔截下來(不關心是post還是get方式)

              appServer.use('/public', function(request,response,next ){

                                NSLog('請求被攔截下來了')

                                // 請求又被放行了

                                next()

                        }

                )

      3.  嚴格匹配 請求方式 與 請求路徑的中介軟體, 如get 和 post等

        像這樣的只有是/login的Get請求,才會被攔截下來

              appServer.get('/login', function(request,response,next ){

                                NSLog('請求被攔截下來了')

                                // 請求一般被處理了,不會再放行了, 要放行也可以...

                                next()

                        }

                )

        4. 錯誤處理中介軟體,  集中處理錯誤, use的引數只有1個函式,  該匿名函式 必須是四個引數

                    appServer.use(function(error,request,response,next ){

                                console.error(error.stack)

                                // 請求一般被處理了,不會再放行了, 要放行也可以...

                                next()

                        }

                )

node_53.js完整程式碼如下:

function NSLog(loli,needLogo=true) {console.log(loli);if(needLogo){console.log('\nCopyright © 2018 Powered by beyond')};}  

// 演示express中的三種中介軟體
var express = require('express')
var appServer = express()  

/*
 第1種,不關心任何請求路徑的中介軟體: 
 use有兩個引數: 
 引數1: 函式(帶3個引數)
 任何請求,都會被攔截下來
 除非 手動呼叫next()才會將請求放行
*/
appServer.use(function (request,response,next) {
	NSLog('第1種_1:' + request.url,false)
	next()
})
appServer.use(function (request,response,next) {
	NSLog('第1種_2:' + request.url,false)
	next()
})


/*
 第2種,不關心請求方式, 只關心請求路徑是以xxx開頭的中介軟體: use有兩個引數: 
 引數1: 以xxx開頭的路徑
 引數2: 函式(帶3個引數)
 任何以xxx開頭的請求,都會被攔截下來
 除非 手動呼叫next()才會將請求放行
*/
appServer.use('/public',function (request,response,next) {
	// 如果此時瀏覽器輸入: localhost/public/img/beyond.jpg
	// 注意這時的url打印出來 就不再包含/public字首了
	// 而是隻有後半部分: /img/beyond.jpg
	NSLog('第2種_以public開頭:' + request.url,false)
})
/*
 第3種,路由級別的中介軟體
 既嚴格匹配請求方式(get/post/put/delete等), 又嚴格匹配請求路徑的中介軟體
 use有兩個引數: 
 引數1: 嚴格匹配的路徑
 引數2: 函式(帶3個引數)
 任何精準匹配路徑 並且 符合請求方式 的請求,都會被攔截下來
 除非 手動呼