1. 程式人生 > 實用技巧 >雜項 ----Express

雜項 ----Express

一、Express的認識
    1.Express框架是什麼
        Express是一個基於Node平臺的web應用開發框架,它提供了一系列的強大特性,幫助你建立各種Web應用。我們可以使用 npm install express 命令進行下載。
    2.Express框架特性
        1.提供了方便簡潔的路由定義方式
        2.對獲取HTTP請求引數進行了簡化處理
        3.對模板引擎支援程度高,方便渲染動態HTML頁面
        4.提供了中介軟體機制有效控制HTTP請求
        5.擁有大量第三方中介軟體對功能進行擴充套件
    3.原生Node.js與Express框架對比之路由
        1.原生Node.js
         app.on('request', (req, res) => {
             // 獲取客戶端的請求路徑
             let { pathname } = url.parse(req.url);
             // 對請求路徑進行判斷 不同的路徑地址響應不同的內容
             if (pathname == '/' || pathname == 'index') {
                res.end('歡迎來到首頁');
             } else if (pathname == '/list') {
                res.end('歡迎來到列表頁頁');
             } else if (pathname == '/about') {
                res.end('歡迎來到關於我們頁面')
             } else {
                res.end('抱歉, 您訪問的頁面出遊了');
             }
         });
        2.Express框架
         // 當客戶端以get方式訪問/時
         app.get('/', (req, res) => {
         
 -----------// 對客戶端做出響應-----------------------------------------------------
            // 1. send方法內部會檢測響應內容的型別
            // 2. send方法會自動設定http狀態碼
            // 3. send方法會幫我們自動設定響應的內容型別及編碼
            
             res.send('Hello Express');
             });
         // 當客戶端以post方式訪問/add路由時
         app.post('/add', (req, res) => {
            res.send('使用post方式請求了/add路由');
         });
    4.原生Node.js與Express框架對比之獲取請求引數
        1. 原生Node.js
        app.on('request', (req, res) => {
            // 獲取GET引數
            let {query} = url.parse(req.url, true);
            // 獲取POST引數
            let postData = '';
            req.on('data', (chunk) => {
                postData += chunk;
            });
            req.on('end', () => {
                console.log(querystring.parse(postData)
            })); 
         });
        2.Express框架
         app.get('/', (req, res) => {
            // 獲取GET引數
            console.log(req.query);
         });

         app.post('/', (req, res) => {
            // 獲取POST引數
            console.log(req.body);
         }) 
    5.使用方法:
         // 引入Express框架
         const express = require('express');
         // 使用框架建立web伺服器
         const app = express();
         // 當客戶端以get方式訪問/路由時
         app.get('/', (req, res) => {
            // 對客戶端做出響應 send方法會根據內容的型別自動設定請求頭---即text/html 等資料
            res.send('Hello Express'); // <h2>Hello Express</h2> {say: 'hello'}
         });
         // 程式監聽3000埠
         app.listen(3000);






二、中介軟體
    1.中介軟體的認識
        什麼是中介軟體?
        中介軟體主要由兩部分構成,中介軟體方法以及請求處理函式。
        中介軟體方法由Express提供,負責攔截請求,請求處理函式由開發人員提供,負責處理請求。
        
        #前面的app.get就是中介軟體方法由系統提供,後面就是處理函式,由開發人員提供
        app.get('請求路徑', '處理函式')   // 接收並處理get請求
        app.post('請求路徑', '處理函式')  // 接收並處理post請求
    2.中介軟體的使用(next)
        可以針對同一個請求設定多箇中間件,對同一個請求進行多次處理。
        預設情況下,請求從上到下依次匹配中介軟體,一旦匹配成功,終止匹配。
        可以呼叫next方法將請求的控制權交給下一個中介軟體,直到遇到結束請求的中介軟體。

        app.get('/request', (req, res, next) => {
             req.name = "張三";
             next();
         });
        app.get('/request', (req, res) => {
             res.send(req.name);
         });
    3.app.use中介軟體用法
        1.app.use 匹配所有的請求方式,可以直接傳入請求處理函式,代表接收所有的請求。
            app.use((req, res, next) => {
             console.log(req.url);
             next();
            });

        2.app.use 第一個引數也可以傳入請求地址,代表不論什麼請求方式,只要是這個請求地址就接收這個請求。
            app.use('/admin', (req, res, next) => {
             console.log(req.url);
             next();
            });

        3.友情提示:
            next是繼續匹配下一個相同的url,比如請求list,他會和第一個use匹配,然後next跳過另一個use和app.get匹配
                app.use((req,res,next)=>{
                    console.log('app.use')
                    next()
                })
                app.use('/request',(req,res)=>{
                    res.send('request')

                })

                app.get('/list',(req,res,next)=>{
                    res.send('list1')
                })
        4.中介軟體應用
            1.路由保護,客戶端在訪問需要登入的頁面時,可以先使用中介軟體判斷使用者登入狀態,使用者如果未登入,則攔截請求,直接響應,禁止使用者進入需要登入的頁面。
            2.網站維護公告,在所有路由的最上面定義接收所有請求的中介軟體,直接為客戶端做出響應,網站正在維護中。(放在最前面,接收所有請求並返回維護頁面)
            3.自定義404頁面(放在最後面,因為next會一個一個匹配,如果沒匹配到就是not found)
            --res.status(404).send('當前訪問的頁面是不存在的')
        5.錯誤處理中介軟體(err)
            在程式執行的過程中,不可避免的會出現一些無法預料的錯誤,比如檔案讀取失敗,資料庫連線失敗。
            錯誤處理中介軟體是一個集中處理錯誤的地方。
            app.use((err, req, res, next) => {
                res.status(500).send('伺服器發生未知錯誤');
            })
            
            
            錯誤處理中介軟體只能處理同步函式,非同步函式不行,非同步函式的錯誤需要主動通過next觸發
            當程式出現錯誤時,呼叫next()方法,並且將錯誤資訊通過引數的形式傳遞給next()方法,即可觸發錯誤處理中介軟體。
            app.get("/", (req, res, next) => {
             fs.readFile("/file-does-not-exist", (err, data) => {
                 if (err) {
                    next(err);
                 }
             });
            });
        6.捕獲錯誤 tyr{} catch(){}
            在node.js中,非同步API的錯誤資訊都是通過回撥函式獲取的,支援Promise物件的非同步API發生錯誤可以通過catch方法捕獲。
            
            try catch 只能捕獲同步或非同步函式的,不能捕獲回撥函式或Promise物件的
            try catch 可以捕獲非同步函式以及其他同步程式碼在執行過程中發生的錯誤,但是不能其他型別的API發生的錯誤。
            app.get("/", async (req, res, next) => {
             try {
                 await User.find({name: '張三'})
             }catch(ex) {
                 next(ex);
             }
            });


        


三、Express的進階使用(路由)
    1.構建模組化路由(可以分級)
        const express = require('express') 
        // 建立路由物件
        const home = express.Router();
        // 將路由和請求路徑進行匹配---------->一級
        app.use('/home', home);
        // 在home路由下繼續建立路由---------->二級
        home.get('/index', () => {
              //  /home/index
             res.send('歡迎來到部落格展示頁面');
        });
        --------------------------------------------->訪問的為home/index
        
    2.GET引數的獲取
        Express框架中使用req.query即可獲取GET引數,框架內部會將GET引數轉換為物件並返回。
        // 接收位址列中問號後面的引數
        // 例如: http://localhost:3000/?name=zhangsan&age=30
        app.get('/', (req, res) => {
        console.log(req.query); // 獲得{"name": "zhangsan", "age": "30"}
        });
    3.POST引數的獲取
        Express中接收post請求引數需要藉助第三方包 body-parser。
        // 引入body-parser模組
        const bodyParser = require('body-parser');

        // 配置body-parser模組   
        // extended: false 方法內部使用querystring模組處理請求引數的格式
        // extended: true 方法內部使用第三方模組qs處理請求引數的格式
        app.use(bodyParser.urlencoded({ extended: false }));
        // 接收請求
        app.post('/add', (req, res) => {
        // 接收請求引數
        console.log(req.body);
        }) 
    4.Express路由引數
        -----------》localhost:3000/find/123
        app.get('/find/:id', (req, res) => { 
            console.log(req.params); // {id: 123} 
        });
    5.靜態資源的處理
    通過Express內建的express.static可以方便地託管靜態檔案,例如img、CSS、JavaScript 檔案等。
        app.use(express.static('public'));
        


四、Express中的模板引擎
    1.使用:
        同時安裝:使用npm install art-template express-art-template命令進行安裝。
    2.範例
    // 當渲染字尾為art的模板時 使用express-art-template
    app.engine('art', require('express-art-template'));
    // 設定模板存放目錄
    app.set('views', path.join(__dirname, 'views'));
    // 渲染模板時不寫字尾 預設拼接art字尾
    app.set('view engine', 'art');
    app.get('/', (req, res) => {
     // 渲染模板
     res.render('index');
    }); 
    究極範例:
        const express = require('express');
        const path = require('path');
        const app = express();

        // 1.告訴express框架使用什麼模板引擎渲染什麼字尾的模板檔案
        //  1.模板字尾
        //  2.使用的模板疫情
        app.engine('art', require('express-art-template'))
        // 2.告訴express框架模板存放的位置是什麼
        app.set('views', path.join(__dirname, 'views'))
        // 3.告訴express框架模板的預設字尾是什麼
        app.set('view engine', 'art');

        app.get('/index', (req, res) => {
            // 1. 拼接模板路徑
            // 2. 拼接模板字尾
            // 3. 哪一個模板和哪一個資料進行拼接
            // 4. 將拼接結果響應給了客戶端
            res.render('index', {
                msg: 'message'
            })
        });

        app.get('/list', (req, res) => {
            res.render('list', {
                msg: 'list page'
            })
        })


        // 埠監聽
        app.listen(3000);
    
    ----------------------------------PS--------------------------------------
    1.要注意模板中的外鏈檔案,修改他們的預設路徑,因為那些靜態資源是瀏覽器解析的
    他的相對路徑是,相對於你在瀏覽器中開啟的網頁的地址  如admin/login,瀏覽器把localhost/admin看成是路徑,Login看成檔案,所以相對路徑是admin
    他會把相對路徑admin和外鏈路徑css/base.css拼在一起形成admin/css/base.css,然後去靜態資原始檔夾如:public裡獲取
    所以我們可以在外鏈路徑新增完整的路徑
    
    2.app.locals 物件
    將變數設定到app.locals物件下面,這個資料在所有的模板中都可以獲取到。
    app.locals.users = [{
         name: '張三',
         age: 20
        },{
         name: '李四',
         age: 20
        }]