nodeJS — 學習的筆記

Node介紹

為什么要學習Node.js

  • 企業需求
    • 具有服務端開發經驗更改
    • front-end
    • back-end
    • 全棧開發工程師
    • 基本的網站開發能力
      • 服務端
      • 前端
      • 運維部署
    • 多人社區

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MVqHkEIo-1588084625862)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200317114503403.png)]

Node.js是什么

  • Node.js是JavaScript 運行時
  • 通俗易懂的講,Node.js是JavaScript的運行平臺
  • Node.js既不是語言,也不是框架,它是一個平臺
  • 瀏覽器中的JavaScript
    • EcmaScript
      • 基本語法
      • if
      • var
      • function
      • Object
      • Array
    • Bom
    • Dom
  • Node.js中的JavaScript
    • 沒有Bom,Dom
    • EcmaScript
    • 在Node中這個JavaScript執行環境為JavaScript提供了一些服務器級別的API
      • 例如文件的讀寫
      • 網絡服務的構建
      • 網絡通信
      • http服務器
  • 構建與Chrome的V8引擎之上
    • 代碼只是具有特定格式的字符串
    • 引擎可以認識它,幫你解析和執行
    • Google Chrome的V8引擎是目前公認的解析執行JavaScript代碼最快的
    • Node.js的作者把Google Chrome中的V8引擎移植出來,開發了一個獨立的JavaScript運行時環境
  • Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.
    • envent-driven 事件驅動
    • non-blocking I/O mode 非阻塞I/O模型(異步)
    • ightweight and efficent. 輕量和高效
  • Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
    • npm 是世界上最大的開源生態系統
    • 絕大多數JavaScript相關的包都存放在npm上,這樣做的目的是為了讓開發人員更方便的去下載使用
    • npm install jquery

Node能做什么

  • web服務器后臺
  • 命令行工具
    • npm(node)
    • git(c語言)
    • hexo(node)
  • 對于前端工程師來講,接觸最多的是它的命令行工具
    • 自己寫的很少,主要是用別人第三方的
    • webpack
    • gulp
    • npm

起步

安裝Node環境

  • 查看Node環境的版本號
  • 下載:https://nodejs.org/en/
  • 安裝:
    • 傻瓜式安裝,一路next
    • 安裝過再次安裝會升級
  • 確認Node環境是否安裝成功
    • 查看node的版本號:node --version
    • 或者node -v
  • 配置環境變量

解析執行JavaScript

  1. 創建編寫JavaScript腳本文件
  2. 打開終端,定位腳本文件的所屬目錄
  3. 輸入node 文件名執行對應的文件

注意:文件名不要用node.js來命名,也就是說除了node這個名字隨便起,最好不要使用中文。

文件的讀寫

文件讀取:

//瀏覽器中的JavaScript是沒有文件操作能力的
//但是Node中的JavaScript具有文件操作能力
//fs是file-system的簡寫,就是文件系統的意思
//在Node中如果想要進行文件的操作就必須引用fs這個核心模塊
//在fs這個和興模塊中,就提供了人所有文件操作相關的API
//例如 fs.readFile就是用來讀取文件的//  1.使用fs核心模塊
var fs = require('fs');// 2.讀取文件
fs.readFile('./data/a.txt',function(err,data){if(err){console.log('文件讀取失敗');}else{console.log(data.toString());}
})

文件寫入:

//  1.使用fs核心模塊
var fs = require('fs');// 2.將數據寫入文件
fs.writeFile('./data/a.txt','我是文件寫入的信息',function(err,data){if(err){console.log('文件寫入失敗');}else{console.log(data.toString());}
})

http

服務器:

// 1.加載http核心模塊
var http = require('http');// 2.使用http.createServer()創建一個web服務器
var server = http.createServer();// 3.服務器要做的事兒
// 提供服務:對數據服務
// 發請求
//	接收請求
//	處理請求
//	反饋(發送響應)
//	當客戶端請求過來,就會自動觸發服務器的request請求事件,然后執行第二個參數:回調處理函數
server.on('request',function(){console.log('收到客戶的請求了')
})// 4.綁定端口號,啟動服務
server.listen(3000,function(){console.log('runing...')
})

Node中的模塊系統

使用Node編寫應用程序主要就是在使用:

  • EcmaScript語言

    • 和瀏覽器一樣,在Node中沒有Bom和Dom
  • 核心模塊

    • 文件操作的fs
    • http服務操作的http
    • url路徑操作模塊
    • path路徑處理模塊
    • os操作系統信息
  • 第三方模塊

    • art-template
    • 必須通過npm來下載才可以使用
  • 自己寫的模塊

    • 自己創建的文件

什么是模塊化

  • 文件作用域(模塊是獨立的,在不同的文件使用必須要重新引用)【在node中沒有全局作用域,它是文件模塊作用域】
  • 通信規則
    • 加載require
    • 導出exports

CommonJS模塊規范

在Node中的JavaScript還有一個重要的概念,模塊系統。

  • 模塊作用域

  • 使用require方法來加載模塊

  • 使用exports接口對象來導出模板中的成員

    加載require

    語法:

    var 自定義變量名 = require('模塊')
    

    作用:

    • 執行被加載模塊中的代碼
    • 得到被加載模塊中的exports導出接口對象

    導出exports

    • Node中是模塊作用域,默認文件中所有的成員只在當前模塊有效

    • 對于希望可以被其他模塊訪問到的成員,我們需要把這些公開的成員都掛載到exports接口對象中就可以了

      導出多個成員(必須在對象中):

      exports.a = 123;
      exports.b = function(){console.log('bbb')
      };
      exports.c = {foo:"bar"
      };
      exports.d = 'hello';
      

      導出單個成員(拿到的就是函數,字符串):

      module.exports = 'hello';
      

      以下情況會覆蓋:

      module.exports = 'hello';
      //后者會覆蓋前者
      module.exports = function add(x,y) {return x+y;
      }
      

      也可以通過以下方法來導出多個成員:

      module.exports = {foo = 'hello',add:function(){return x+y;}
      };
      

模塊原理

exports和module.exports的一個引用:

console.log(exports === module.exports);	//trueexports.foo = 'bar';//等價于
module.exports.foo = 'bar';

當給exports重新賦值后,exports!= module.exports.

最終return的是module.exports,無論exports中的成員是什么都沒用。

真正去使用的時候:導出單個成員:exports.xxx = xxx;導出多個成員:module.exports 或者 modeule.exports = {};

總結

// 引用服務
var http = require('http');
var fs = require('fs');
// 引用模板
var template = require('art-template');
// 創建服務
var server = http.createServer();
// 公共路徑
var wwwDir = 'D:/app/www';
server.on('request', function (req, res) {var url = req.url;// 讀取文件fs.readFile('./template-apche.html', function (err, data) {if (err) {return res.end('404 Not Found');}fs.readdir(wwwDir, function (err, files) {if (err) {return res.end('Can not find www Dir.')}// 使用模板引擎解析替換data中的模板字符串// 去xmpTempleteList.html中編寫模板語法var htmlStr = template.render(data.toString(), { title: 'D:/app/www/ 的索引',files:files });// 發送響應數據res.end(htmlStr);})})
});
server.listen(3000, function () {console.log('running....');
})
1.jQuery中的each 和 原生JavaScript方法forEach的區別:提供源頭:原生js是es5提供的(不兼容IE8,jQuery的each是jQuery第三方庫提供的(如果要使用需要用2以下的版本也就是1.版本),它的each方法主要用來遍歷jQuery實例對象(偽數組),同時也可以做低版本forEach的替代品,jQuery的實例對象不能使用forEach方法,如果想要使用必須轉為數組([].slice.call(jQuery實例對象))才能使用
2.模塊中導出多個成員和導出單個成員
3.301302的區別:301永久重定向,瀏覽器會記住302臨時重定向
4.exports和module.exports的區別:每個模塊中都有一個module對象module對象中有一個exports對象我們可以把需要導出的成員都掛載到module.exports接口對象中也就是`module.exports.xxx = xxx`的方式但是每次寫太多了就很麻煩,所以Node為了簡化代碼,就在每一個模塊中都提供了一個成員叫`exports``exports === module.exports`結果為true,所以完全可以`exports.xxx = xxx`當一個模塊需要導出單個成員的時候必須使用`module.exports = xxx`的方式,=,使用`exports = xxx`不管用,因為每個模塊最終return的是module.exports,而exports只是module.exports的一個引用,所以`exports`即使重新賦值,也不會影響`module.exports`。有一種賦值方式比較特殊:`exports = module.exports`這個用來新建立引用關系的。

require的加載規則

  • 核心模塊

    • 模塊名
  • 第三方模塊

    • 模塊名
  • 用戶自己寫的

    • 路徑

require的加載規則:

  • 優先從緩存加載

  • 判斷模塊標識符

    • 核心模塊
    • 自己寫的模塊(路徑形式的模塊)
    • 第三方模塊(node_modules)
      • 第三方模塊的標識就是第三方模塊的名稱(不可能有第三方模塊和核心模塊的名字一致)
      • npm
        • 開發人員可以把寫好的框架庫發布到npm上
        • 使用者通過npm命令來下載
      • 使用方式:var 名稱 = require('npm install【下載包】 的包名')
        • node_modules/express/package.json main
        • 如果package.json或者main不成立,則查找被選擇項:index.js
        • 如果以上條件都不滿足,則繼續進入上一級目錄中的node_modules按照上面的規則依次查找,直到當前文件所屬此盤根目錄都找不到最后報錯
// 如果非路徑形式的標識
// 路徑形式的標識:// ./  當前目錄 不可省略// ../  上一級目錄  不可省略//  /xxx也就是D:/xxx// 帶有絕對路徑幾乎不用(D:/a/foo.js)
// 首位表示的是當前文件模塊所屬磁盤根目錄
// require('./a'); // 核心模塊
// 核心模塊本質也是文件,核心模塊文件已經被編譯到了二進制文件中了,我們只需要按照名字來加載就可以了
require('fs'); // 第三方模塊
// 凡是第三方模塊都必須通過npm下載(npm i node_modules),使用的時候就可以通過require('包名')來加載才可以使用
// 第三方包的名字不可能和核心模塊的名字是一樣的
// 既不是核心模塊,也不是路徑形式的模塊
//      先找到當前文所述目錄的node_modules
//      然后找node_modules/art-template目錄
//      node_modules/art-template/package.json
//      node_modules/art-template/package.json中的main屬性
//      main屬性記錄了art-template的入口模塊
//      然后加載使用這個第三方包
//      實際上最終加載的還是文件//      如果package.json不存在或者mian指定的入口模塊不存在
//      則node會自動找該目錄下的index.js
//      也就是說index.js是一個備選項,如果main沒有指定,則加載index.js文件
//      // 如果條件都不滿足則會進入上一級目錄進行查找
// 注意:一個項目只有一個node_modules,放在項目根目錄中,子目錄可以直接調用根目錄的文件
var template = require('art-template');

模塊標識符中的/和文件操作路徑中的/

文件操作路徑:

// 咱們所使用的所有文件操作的API都是異步的
// 就像ajax請求一樣
// 讀取文件
// 文件操作中 ./ 相當于當前模塊所處磁盤根目錄
// ./index.txt    相對于當前目錄
// /index.txt    相對于當前目錄
// /index.txt   絕對路徑,當前文件模塊所處根目錄
// d:express/index.txt   絕對路徑
fs.readFile('./index.txt',function(err,data){if(err){return  console.log('讀取失敗');}console.log(data.toString());
})

模塊操作路徑:

// 在模塊加載中,相對路徑中的./不能省略
// 這里省略了.也是磁盤根目錄
require('./index')('hello')

npm

  • node package manage(node包管理器)
  • 通過npm命令安裝jQuery包(npm install --save jquery),在安裝時加上–save會主動生成說明書文件信息(將安裝文件的信息添加到package.json里面)

npm網站

? npmjs.com 網站 是用來搜索npm包的

npm命令行工具

npm是一個命令行工具,只要安裝了node就已經安裝了npm。

npm也有版本概念,可以通過npm --version來查看npm的版本

升級npm(自己升級自己):

npm install --global npm

常用命令

  • npm init(生成package.json說明書文件)
    • npm init -y(可以跳過向導,快速生成)
  • npm install
    • 一次性把dependencies選項中的依賴項全部安裝
    • 簡寫(npm i)
  • npm install 包名
    • 只下載
    • 簡寫(npm i 包名)
  • npm install --save 包名
    • 下載并且保存依賴項(package.json文件中的dependencies選項)
    • 簡寫(npm i 包名)
  • npm uninstall 包名
    • 只刪除,如果有依賴項會依然保存
    • 簡寫(npm un 包名)
  • npm uninstall --save 包名
    • 刪除的同時也會把依賴信息全部刪除
    • 簡寫(npm un 包名)
  • npm help
    • 查看使用幫助
  • npm 命令 --help
    • 查看具體命令的使用幫助(npm uninstall --help)

解決npm被墻問題

npm存儲包文件的服務器在國外,有時候會被墻,速度很慢,所以需要解決這個問題。

https://developer.aliyun.com/mirror/NPM?from=tnpm淘寶的開發團隊把npm在國內做了一個鏡像(也就是一個備份)。

安裝淘寶的cnpm:

npm install -g cnpm --registry=https://registry.npm.taobao.org;
#在任意目錄執行都可以
#--global表示安裝到全局,而非當前目錄
#--global不能省略,否則不管用
npm install --global cnpm

安裝包的時候把以前的npm替換成cnpm

#走國外的npm服務器下載jQuery包,速度比較慢
npm install jQuery;#使用cnpm就會通過淘寶的服務器來下載jQuery
cnpm install jQuery;

如果不想安裝cnpm又想使用淘寶的服務器來下載:

npm install jquery --registry=https://npm.taobao.org;

但是每次手動加參數就很麻煩,所以我們可以把這個選項加入到配置文件中:

npm config set registry https://npm.taobao.org;#查看npm配置信息
npm config list;

只要經過上面的配置命令,則以后所有的npm install都會通過淘寶的服務器來下載

package.json

每一個項目都要有一個package.json文件(包描述文件,就像產品的說明書一樣)

這個文件可以通過npm init自動初始化出來


D:\code\node中的模塊系統>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.See `npm help json` for definitive documentation on these fields
and exactly what they do.Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.Press ^C at any time to quit.
package name: (node中的模塊系統)
Sorry, name can only contain URL-friendly characters.
package name: (node中的模塊系統) cls
version: (1.0.0)
description: 這是一個測試項目
entry point: (main.js)
test command:
git repository:
keywords:
author: xiaochen
license: (ISC)
About to write to D:\code\node中的模塊系統\package.json:{"name": "cls","version": "1.0.0","description": "這是一個測試項目","main": "main.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "xiaochen","license": "ISC"
}Is this OK? (yes) yes

對于目前來講,最有用的是dependencies選項,可以用來幫助我們保存第三方包的依賴信息。

如果node_modules刪除了也不用擔心,只需要在控制面板中npm install就會自動把package.json中的dependencies中所有的依賴項全部都下載回來。

  • 建議每個項目的根目錄下都有一個package.json文件
  • 建議執行npm install 包名的時候都加上--save選項,目的是用來保存依賴信息

package.json和package-lock.json

npm 5以前是不會有package-lock.json這個文件

npm5以后才加入這個文件

當你安裝包的時候,npm都會生成或者更新package-lock.json這個文件

  • npm5以后的版本安裝都不要加--save參數,它會自動保存依賴信息
  • 當你安裝包的時候,會自動創建或者更新package-lock.json文件
  • package-lock.json這個文件會包含node_modules中所有包的信息(版本,下載地址。。。)
    • 這樣的話重新npm install的時候速度就可以提升
  • 從文件來看,有一個lock稱之為鎖
    • 這個lock使用來鎖版本的
    • 如果項目依賴了1.1.1版本
    • 如果你重新install其實會下載最細版本,而不是1.1.1
    • package-lock.json的另外一個作用就是鎖定版本號,防止自動升級

path路徑操作模塊

參考文檔:https://nodejs.org/docs/latest-v13.x/api/path.html

  • path.basename:獲取路徑的文件名,默認包含擴展名
  • path.dirname:獲取路徑中的目錄部分
  • path.extname:獲取一個路徑中的擴展名部分
  • path.parse:把路徑轉換為對象
    • root:根路徑
    • dir:目錄
    • base:包含后綴名的文件名
    • ext:后綴名
    • name:不包含后綴名的文件名
  • path.join:拼接路徑
  • path.isAbsolute:判斷一個路徑是否為絕對路徑[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IKjJLR5v-1588084625866)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200315150610001.png)]

Node中的其它成員(__dirname,__filename)

在每個模塊中,除了require,exports等模塊相關的API之外,還有兩個特殊的成員:

  • __dirname,是一個成員,可以用來動態獲取當前文件模塊所屬目錄的絕對路徑

  • __filename,可以用來動態獲取當前文件的絕對路徑(包含文件名)

  • __dirnamefilename是不受執行node命令所屬路徑影響的

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UdLy7Ykz-1588084625867)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200315151551873.png)]

在文件操作中,使用相對路徑是不可靠的,因為node中文件操作的路徑被設計為相對于執行node命令所處的路徑。

所以為了解決這個問題,只需要把相對路徑變為絕對路徑(絕對路徑不受任何影響)就可以了。

就可以使用__dirname或者__filename來幫助我們解決這個問題

在拼接路徑的過程中,為了避免手動拼接帶來的一些低級錯誤,推薦使用path.join()來輔助拼接

var fs = require('fs');
var path = require('path');// console.log(__dirname + 'a.txt');
// path.join方法會將文件操作中的相對路徑都統一的轉為動態的絕對路徑
fs.readFile(path.join(__dirname + '/a.txt'),'utf8',function(err,data){if(err){throw err}console.log(data);
});

補充:模塊中的路徑標識和這里的路徑沒關系,不受影響(就是相對于文件模塊)

注意:

模塊中的路徑標識和文件操作中的相對路徑標識不一致

模塊中的路徑標識就是相對于當前文件模塊,不受node命令所處路徑影響

Express(快速的)

作者:Tj

原生的http在某些方面表現不足以應對我們的開發需求,所以就需要使用框架來加快我們的開發效率,框架的目的就是提高效率,讓我們的代碼高度統一。

在node中有很多web開發框架。主要學習express

  • http://expressjs.com/,其中主要封裝的是http。

  • // 1 安裝
    // 2 引包
    var express = require('express');
    // 3 創建服務器應用程序
    //      也就是原來的http.createServer();
    var app = express();// 公開指定目錄
    // 只要通過這樣做了,就可以通過/public/xx的方式來訪問public目錄中的所有資源
    // 在Express中開放資源就是一個API的事
    app.use('/public/',express.static('/public/'));//模板引擎在Express中開放模板也是一個API的事// 當服務器收到get請求 / 的時候,執行回調處理函數
    app.get('/',function(req,res){res.send('hello express');
    })// 相當于server.listen
    app.listen(3000,function(){console.log('app is runing at port 3000');
    })
    

學習Express

起步

安裝:[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pHrwvRUP-1588084625869)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200310123723079.png)]
cnpm install express
hello world:[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IK7VyfEG-1588084625870)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200310124850557.png)]
// 引入express
var express = require('express');// 1. 創建app
var app = express();//  2. 
app.get('/',function(req,res){// 1// res.write('Hello');// res.write('World');// res.end()// 2// res.end('hello world');// 3res.send('hello world');
})app.listen(3000,function(){console.log('express app is runing...');
})
基本路由

路由:

  • 請求方法

  • 請求路徑

  • 請求處理函數

get:

//當你以get方法請求/的時候,執行對應的處理函數
app.get('/',function(req,res){res.send('hello world');
})

post:

//當你以post方法請求/的時候,執行對應的處理函數
app.post('/',function(req,res){res.send('hello world');
})
Express靜態服務API
// app.use不僅僅是用來處理靜態資源的,還可以做很多工作(body-parser的配置)
app.use(express.static('public'));app.use(express.static('files'));app.use('/stataic',express.static('public'));
// 引入express
var express = require('express');// 創建app
var app = express();// 開放靜態資源
// 1.當以/public/開頭的時候,去./public/目錄中找對應資源
// 訪問:http://127.0.0.1:3000/public/login.html
app.use('/public/',express.static('./public/')); // 2.當省略第一個參數的時候,可以通過省略/public的方式來訪問
// 訪問:http://127.0.0.1:3000/login.html
// app.use(express.static('./public/'));   // 3.訪問:http://127.0.0.1:3000/a/login.html
// a相當于public的別名
// app.use('/a/',express.static('./public/')); //  
app.get('/',function(req,res){res.end('hello world');
});app.listen(3000,function(){console.log('express app is runing...');
});
在Express中配置使用art-templete模板引擎
  • art-template官方文檔
  • 在node中,有很多第三方模板引擎都可以使用,不是只有art-template
    • 還有ejs,jade(pug),handlebars,nunjucks

安裝:

npm install --save art-template
npm install --save express-art-template//兩個一起安裝
npm i --save art-template express-art-template

配置:

app.engine('html', require('express-art-template'));

使用:

app.get('/',function(req,res){// express默認會去views目錄找index.htmlres.render('index.html',{title:'hello world'     });
})

如果希望修改默認的views視圖渲染存儲目錄,可以:

// 第一個參數views千萬不要寫錯
app.set('views',目錄路徑);
在Express中獲取表單請求數據
獲取get請求數據:

Express內置了一個api,可以直接通過req.query來獲取數據

// 通過requery方法獲取用戶輸入的數據
// req.query只能拿到get請求的數據var comment = req.query;
獲取post請求數據:

在Express中沒有內置獲取表單post請求體的api,這里我們需要使用一個第三方包body-parser來獲取數據。

安裝:

npm install --save body-parser;

配置:

// 配置解析表單 POST 請求體插件(注意:一定要在 app.use(router) 之前 )

var express = require('express')
// 引包
var bodyParser = require('body-parser')var app = express()// 配置body-parser
// 只要加入這個配置,則在req請求對象上會多出來一個屬性:body
// 也就是說可以直接通過req.body來獲取表單post請求數據
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))// parse application/json
app.use(bodyParser.json())

使用:

app.use(function (req, res) {res.setHeader('Content-Type', 'text/plain')res.write('you posted:\n')// 可以通過req.body來獲取表單請求數據res.end(JSON.stringify(req.body, null, 2))
})

在Express中配置使用express-session插件操作

參考文檔:https://github.com/expressjs/session

安裝:

npm install express-session

配置:

//該插件會為req請求對象添加一個成員:req.session默認是一個對象
//這是最簡單的配置方式
//Session是基于Cookie實現的
app.use(session({//配置加密字符串,他會在原有的基礎上和字符串拼接起來去加密//目的是為了增加安全性,防止客戶端惡意偽造secret: 'keyboard cat',resave: false,saveUninitialized: true,//無論是否適用Session,都默認直接分配一把鑰匙cookie: { secure: true }
}))

使用:

// 讀
//添加Session數據
//session就是一個對象
req.session.foo = 'bar';//寫
//獲取session數據
req.session.foo//刪
req.session.foo = null;
delete req.session.foo

提示:

默認Session數據時內存儲數據,服務器一旦重啟,真正的生產環境會把Session進行持久化存儲。

利用Express實現ADUS項目

模塊化思想

模塊如何劃分:

  • 模塊職責要單一

javascript模塊化:

  • Node 中的 CommonJS
  • 瀏覽器中的:
    • AMD require.js
    • CMD sea.js
  • es6中增加了官方支持

起步

  • 初始化
  • 模板處理

路由設計

請求方法請求路徑get參數post參數備注
GET/students渲染首頁
GET/students/new渲染添加學生頁面
POST/students/newname,age,gender,hobbies處理添加學生請求
GET/students/editid渲染編輯頁面
POST/students/editid,name,age,gender,hobbies處理編輯請求
GET/students/deleteid處理刪除請求

提取路由模塊

router.js:

/*** router.js路由模塊* 職責:*      處理路由*      根據不同的請求方法+請求路徑設置具體的請求函數* 模塊職責要單一,我們劃分模塊的目的就是增強代碼的可維護性,提升開發效率*/
var fs = require('fs');// Express專門提供了一種更好的方式
// 專門用來提供路由的
var express = require('express');
// 1 創建一個路由容器
var router = express.Router();
// 2 把路由都掛載到路由容器中router.get('/students', function(req, res) {// res.send('hello world');// readFile的第二個參數是可選的,傳入utf8就是告訴他把讀取到的文件直接按照utf8編碼,直接轉成我們認識的字符// 除了這樣來轉換,也可以通過data.toString()來轉換fs.readFile('./db.json', 'utf8', function(err, data) {if (err) {return res.status(500).send('Server error.')}// 讀取到的文件數據是string類型的數據// console.log(data);// 從文件中讀取到的數據一定是字符串,所以一定要手動轉換成對象var students = JSON.parse(data).students;res.render('index.html', {// 讀取文件數據students:students})})
});router.get('/students/new',function(req,res){res.render('new.html')
});router.get('/students/edit',function(req,res){});router.post('/students/edit',function(req,res){});router.get('/students/delete',function(req,res){});// 3 把router導出
module.exports = router;

app.js:

var router = require('./router');// router(app);
// 把路由容器掛載到app服務中
// 掛載路由
app.use(router);

設計操作數據的API文件模塊

es6中的find和findIndex:

find接受一個方法作為參數,方法內部返回一個條件

find會便利所有的元素,執行你給定的帶有條件返回值的函數

符合該條件的元素會作為find方法的返回值

如果遍歷結束還沒有符合該條件的元素,則返回undefined[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hRBBCT0b-1588084625871)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200313103810731.png)]

/*** student.js* 數據操作文件模塊* 職責:操作文件中的數據,只處理數據,不關心業務*/
var fs = require('fs');/*** 獲取所有學生列表* return []*/
exports.find = function(){}/*** 獲取添加保存學生*/
exports.save = function(){}/*** 更新學生*/
exports.update = function(){}/*** 刪除學生*/
exports.delete = function(){}

步驟

  • 處理模板

  • 配置靜態開放資源

  • 配置模板引擎

  • 簡單的路由,/studens渲染靜態頁出來

  • 路由設計

  • 提取路由模塊

  • 由于接下來的一系列業務操作都需要處理文件數據,所以我們需要封裝Student.js’

  • 先寫好student.js文件結構

    • 查詢所有學生列別哦的API
    • findById
    • save
    • updateById
    • deleteById
  • 實現具體功能

    • 通過路由收到請求
    • 接受請求中的參數(get,post)
      • req.query
      • req.body
    • 調用數據操作API處理數據
    • 根據操作結果給客戶端發送請求
  • 業務功能順序

    • 列表
    • 添加
    • 編輯
    • 刪除

子模板和模板的繼承(模板引擎高級語法)【include,extend,block】

注意:

模板頁:

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>模板頁</title><link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>{{ block 'head' }}{{ /block }}
</head>
<body><!-- 通過include導入公共部分 -->{{include './header.html'}}<!-- 留一個位置 讓別的內容去填充 -->{{ block  'content' }}<h1>默認內容</h1>{{ /block }}<!-- 通過include導入公共部分 -->{{include './footer.html'}}<!-- 公共樣式 --><script src="/node_modules/jquery/dist/jquery.js" ></script><script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script>{{ block 'script' }}{{ /block }}
</body>
</html>

模板的繼承:

? header頁面:

<div id=""><h1>公共的頭部</h1>
</div>

? footer頁面:

<div id=""><h1>公共的底部</h1>
</div>

模板頁的使用:

<!-- 繼承(extend:延伸,擴展)模板也layout.html -->
<!-- 把layout.html頁面的內容都拿進來作為index.html頁面的內容 -->
{{extend './layout.html'}}<!-- 向模板頁面填充新的數據 -->
<!-- 填充后就會替換掉layout頁面content中的數據 -->
<!-- style樣式方面的內容 -->
{{ block 'head' }}<style type="text/css">body{background-color: skyblue;}</style>
{{ /block }}
{{ block 'content' }}<div id=""><h1>Index頁面的內容</h1></div>
{{ /block }}
<!-- js部分的內容 -->
{{ block 'script' }}<script type="text/javascript"></script>
{{ /block }}

最終的顯示效果:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dQYV5StQ-1588084625872)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200316134759517.png)]

MongoDB

關系型和非關系型數據庫

關系型數據庫(表就是關系,或者說表與表之間存在關系)。

  • 所有的關系型數據庫都需要通過sql語言來操作
  • 所有的關系型數據庫在操作之前都需要設計表結構
  • 而且數據表還支持約束
    • 唯一的
    • 主鍵
    • 默認值
    • 非空

非關系型數據庫

  • 非關系型數據庫非常的靈活
  • 有的關系型數據庫就是key-value對兒
  • 但MongDB是長得最像關系型數據庫的非關系型數據庫
    • 數據庫 -》 數據庫
    • 數據表 -》 集合(數組)
    • 表記錄 -》文檔對象

一個數據庫中可以有多個數據庫,一個數據庫中可以有多個集合(數組),一個集合中可以有多個文檔(表記錄)

{qq:{user:[{},{},{}...]}
}
  • 也就是說你可以任意的往里面存數據,沒有結構性這么一說

安裝

  • 下載

    • 下載地址:https://www.mongodb.com/download-center/community
  • 安裝

    npm i mongoose
    
  • 配置環境變量

  • 最后輸入mongod --version測試是否安裝成功

啟動和關閉數據庫

啟動:

# mongodb 默認使用執行mongod 命令所處盼復根目錄下的/data/db作為自己的數據存儲目錄
# 所以在第一次執行該命令之前先自己手動新建一個 /data/db
mongod

如果想要修改默認的數據存儲目錄,可以:

mongod --dbpath = 數據存儲目錄路徑

停止:

在開啟服務的控制臺,直接Ctrl+C;
或者直接關閉開啟服務的控制臺。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-raFJ7Bn2-1588084625873)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314101047100.png)]

連接數據庫

連接:

# 該命令默認連接本機的 MongoDB 服務
mongo

退出:

# 在連接狀態輸入 exit 退出連接
exit

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wCuDhnvl-1588084625874)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314100821112.png)]

基本命令

  • show dbs
    • 查看數據庫列表(數據庫中的所有數據庫)
  • db
    • 查看當前連接的數據庫
  • use 數據庫名稱
    • 切換到指定的數據庫,(如果沒有會新建)
  • show collections
    • 查看當前目錄下的所有數據表
  • db.表名.find()
    • 查看表中的詳細信息

在Node中如何操作MongoDB數據庫

使用官方的MongoDB包來操作

? http://mongodb.github.io/node-mongodb-native/

使用第三方包mongoose來操作MongoDB數據庫

? 第三方包:mongoose基于MongoDB官方的mongodb包再一次做了封裝,名字叫mongoose,是WordPress項目團隊開發的。

? https://mongoosejs.com/

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-veLUPN5X-1588084625874)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314105632745.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-dNiyAUWv-1588084625875)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314105717993.png)]

學習指南(步驟)

官方學習文檔:https://mongoosejs.com/docs/index.html

設計Scheme 發布Model (創建表)

// 1.引包
// 注意:按照后才能require使用
var mongoose = require('mongoose');// 拿到schema圖表
var Schema = mongoose.Schema;// 2.連接數據庫
// 指定連接數據庫后不需要存在,當你插入第一條數據庫后會自動創建數據庫
mongoose.connect('mongodb://localhost/test');// 3.設計集合結構(表結構)
// 用戶表
var userSchema = new Schema({username: { //姓名type: String,require: true //添加約束,保證數據的完整性,讓數據按規矩統一},password: {type: String,require: true},email: {type: String}
});// 4.將文檔結構發布為模型
// mongoose.model方法就是用來將一個架構發布為 model
// 		第一個參數:傳入一個大寫名詞單數字符串用來表示你的數據庫的名稱
// 					mongoose 會自動將大寫名詞的字符串生成 小寫復數 的集合名稱
// 					例如 這里會變成users集合名稱
// 		第二個參數:架構
// 	返回值:模型構造函數
var User = mongoose.model('User', userSchema);

添加數據(增)

// 5.通過模型構造函數對User中的數據進行操作
var user = new User({username: 'admin',password: '123456',email: 'xiaochen@qq.com'
});user.save(function(err, ret) {if (err) {console.log('保存失敗');} else {console.log('保存成功');console.log(ret);}
});

刪除(刪)

根據條件刪除所有:

User.remove({username: 'xiaoxiao'
}, function(err, ret) {if (err) {console.log('刪除失敗');} else {console.log('刪除成功');console.log(ret);}
});

根據條件刪除一個:

Model.findOneAndRemove(conditions,[options],[callback]);

根據id刪除一個:

User.findByIdAndRemove(id,[options],[callback]);

更新(改)

更新所有:

User.remove(conditions,doc,[options],[callback]);

根據指定條件更新一個:

User.FindOneAndUpdate([conditions],[update],[options],[callback]);

根據id更新一個:

// 更新	根據id來修改表數據
User.findByIdAndUpdate('5e6c5264fada77438c45dfcd', {username: 'junjun'
}, function(err, ret) {if (err) {console.log('更新失敗');} else {console.log('更新成功');}
});

查詢(查)

查詢所有:

// 查詢所有
User.find(function(err,ret){if(err){console.log('查詢失敗');}else{console.log(ret);}
});

條件查詢所有:

// 根據條件查詢
User.find({ username:'xiaoxiao' },function(err,ret){if(err){console.log('查詢失敗');}else{console.log(ret);}
});

條件查詢單個:

// 按照條件查詢單個,查詢出來的數據是一個對象({})
// 沒有條件查詢使用findOne方法,查詢的是表中的第一條數據
User.findOne({username: 'xiaoxiao'
}, function(err, ret) {if (err) {console.log('查詢失敗');} else {console.log(ret);}
});

使用Node操作MySQL數據庫

文檔:https://www.npmjs.com/package/mysql

安裝:

npm install --save  mysql
// 引入mysql包
var mysql      = require('mysql');// 創建連接
var connection = mysql.createConnection({host     : 'localhost',	//本機user     : 'me',		//賬號rootpassword : 'secret',	//密碼12345database : 'my_db'	//數據庫名
});// 連接數據庫	(打開冰箱門)
connection.connect();//執行數據操作	(把大象放到冰箱)
connection.query('SELECT * FROM `users` ', function (error, results, fields) {if (error) throw error;//拋出異常阻止代碼往下執行// 沒有異常打印輸出結果console.log('The solution is: ',results);
});//關閉連接	(關閉冰箱門)
connection.end();

異步編程

回調函數

不成立的情況下:

function add(x,y){console.log(1);setTimeout(function(){console.log(2);var ret = x + y;return ret;},1000);console.log(3);//到這里執行就結束了,不會i等到前面的定時器,所以直接返回了默認值 undefined
}console.log(add(2,2));
// 結果是 1 3 undefined 4

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3e80U9mD-1588084625876)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200313085008929.png)]

使用回調函數解決:

回調函數:通過一個函數,獲取函數內部的操作。(根據輸入得到輸出結果)

var ret;
function add(x,y,callback){// callback就是回調函數// var x = 10;// var y = 20;// var callback = function(ret){console.log(ret);}console.log(1);setTimeout(function(){var ret = x + y;callback(ret);},1000);console.log(3);
}
add(10,20,function(ret){console.log(ret);
});
image-20200313084746701

注意:

? 凡是需要得到一個函數內部異步操作的結果(setTimeout,readFile,writeFile,ajax,readdir)

? 這種情況必須通過 回調函數 (異步API都會伴隨著一個回調函數)

ajax:

基于原生XMLHttpRequest封裝get方法:

var oReq = new XMLHttpRequest();
// 當請求加載成功要調用指定的函數
oReq.onload = function(){console.log(oReq.responseText);
}
oReq.open("GET", "請求路徑",true);
oReq.send();
function get(url,callback){var oReq = new XMLHttpRequest();// 當請求加載成功要調用指定的函數oReq.onload = function(){//console.log(oReq.responseText);callback(oReq.responseText);}oReq.open("GET", url,true);oReq.send();
}
get('data.json',function(data){console.log(data);
});

Promise

callback hell(回調地獄):

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y6mw0zAR-1588084625877)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314143410972.png)]

文件的讀取無法判斷執行順序(文件的執行順序是依據文件的大小來決定的)(異步api無法保證文件的執行順序)

var fs = require('fs');fs.readFile('./data/a.text','utf8',function(err,data){if(err){// 1 讀取失敗直接打印輸出讀取失敗return console.log('讀取失敗');// 2 拋出異常// 		阻止程序的執行// 		把錯誤信息打印到控制臺throw err;}console.log(data);
});fs.readFile('./data/b.text','utf8',function(err,data){if(err){// 1 讀取失敗直接打印輸出讀取失敗return console.log('讀取失敗');// 2 拋出異常// 		阻止程序的執行// 		把錯誤信息打印到控制臺throw err;}console.log(data);
});

通過回調嵌套的方式來保證順序:

var fs = require('fs');fs.readFile('./data/a.text','utf8',function(err,data){if(err){// 1 讀取失敗直接打印輸出讀取失敗return console.log('讀取失敗');// 2 拋出異常// 		阻止程序的執行// 		把錯誤信息打印到控制臺throw err;}console.log(data);fs.readFile('./data/b.text','utf8',function(err,data){if(err){// 1 讀取失敗直接打印輸出讀取失敗return console.log('讀取失敗');// 2 拋出異常// 		阻止程序的執行// 		把錯誤信息打印到控制臺throw err;}console.log(data);fs.readFile('./data/a.text','utf8',function(err,data){if(err){// 1 讀取失敗直接打印輸出讀取失敗return console.log('讀取失敗');// 2 拋出異常// 		阻止程序的執行// 		把錯誤信息打印到控制臺throw err;}console.log(data);});});
});

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Ifh2960o-1588084625878)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314144807008.png)]為了解決以上編碼方式帶來的問題(回調地獄嵌套),所以在EcmaScript6新增了一個API:Promise。[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-LTzI16Wv-1588084625878)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314150050839.png)]

  • Promise:承諾,保證
  • Promise本身不是異步的,但往往都是內部封裝一個異步任務

基本語法:

// 在EcmaScript 6中新增了一個API Promise
// Promise 是一個構造函數var fs = require('fs');
// 1 創建Promise容器		resolve:解決   reject:失敗
var p1 = new Promise(function(resolve, reject) {fs.readFile('./a.text', 'utf8', function(err, data) {if (err) {// console.log(err);// 把容器的Pending狀態變為rejectedreject(err);} else {// console.log(data);// 把容器的Pending狀態變為resolveresolve(1234);}});
});// 當p1成功了,然后就(then)做指定的操作
// then方法接收的function就是容器中的resolve函數
p1.then(function(data) {console.log(data);}, function(err) {console.log('讀取文件失敗了', err);});

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-7hbGolvd-1588084625879)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200315100611620.png)]

鏈式循環:[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MDRWoCFR-1588084625880)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200315125559136.png)]

封裝Promise的readFile

var fs = require('fs');function pReadFile(filePath) {return new Promise(function(resolve, reject) {fs.readFile(filePath, 'utf8', function(err, data) {if (err) {reject(err);} else {resolve(data);}});});
}pReadFile('./a.txt').then(function(data) {console.log(data);return pReadFile('./b.txt');}).then(function(data) {console.log(data);return pReadFile('./a.txt');}).then(function(data) {console.log(data);})

mongoose所有的API都支持Promise:

// 查詢所有
User.find().then(function(data){console.log(data)})

注冊:

User.findOne({username:'admin'},function(user){if(user){console.log('用戶已存在')} else {new User({username:'aaa',password:'123',email:'fffff'}).save(function(){console.log('注冊成功');})}
})
User.findOne({username:'admin'
}).then(function(user){if(user){// 用戶已經存在不能注冊console.log('用戶已存在');}else{// 用戶不存在可以注冊return new User({username:'aaa',password:'123',email:'fffff'}).save();}}).then(funciton(ret){console.log('注冊成功');})

Generator

async函數

其他

修改完代碼自動重啟

我們在這里可以使用一個第三方命名行工具:nodemon來幫助我們解決頻繁修改代碼重啟服務器的問題。

nodemon是一個基于Node.js開發的一個第三方命令行工具,我們使用的時候需要獨立安裝:

#在任意目錄執行該命令都可以
#也就是說,所有需要 --global安裝的包都可以在任意目錄執行
npm install --global nodemon
npm install -g nodemon#如果安裝不成功的話,可以使用cnpm安裝
cnpm install -g nodemon

安裝完畢之后使用:

node app.js#使用nodemon
nodemon app.js

只要是通過nodemon啟動的服務,則他會監視你的文件變化,當文件發生變化的時候,會自動幫你重啟服務器。

封裝異步API

回調函數:獲取異步操作的結果

function fn(callback){// var callback = funtion(data){ console.log(data); }setTimeout(function(){var data = 'hello';callback(data);},1000);
}
// 如果需要獲取一個函數中異步操作的結果,則必須通過回調函數的方式來獲取
fn(function(data){console.log(data);
})

數組的遍歷方法,都是對函數作為一種參數

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mZOYURpE-1588084625881)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200314094620191.png)]

EcmaScript 6

參考文檔:https://es6.ruanyifeng.com/

項目案例

目錄結構

.
app.js	項目的入口文件
controllers
models	存儲使用mongoose設計的數據模型
node_modules	第三方包
package.json	包描述文件
package-lock.json	第三方包版本鎖定文件(npm5之后才有)
public	公共靜態資源
routes
views	存儲視圖目錄

模板頁

  • 子模板
  • 模板繼承

路由設計

路由方法get參數post參數是否需要登錄備注
/get渲染首頁
/register(登錄)get渲染注冊頁面
/registerpostemail,nickname,password處理注冊請求
/loginget渲染登陸界面
/loginpostemail,password處理登錄請求
/loginoutget處理退出請求

模型設計

功能實現

步驟

  • 創建目錄結構
  • 整合靜態也-模板頁
    • include
    • block
    • extend
  • 設計用戶登陸,退出,注冊的路由
  • 用戶注冊
    • 先處理客戶端頁面的內容(表單控件的name,收集表單數據,發起請求)
    • 服務端
      • 獲取從客戶端收到的數據
      • 操作數據庫
        • 如果有錯,發送500告訴客戶端服務器錯了‘
        • 其他的根據業務發送不同的響應數據
  • 登錄
  • 退出

Express中間件

中間件的概念

參考文檔:http://expressjs.com/en/guide/using-middleware.html

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-WKGQLexX-1588084625882)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200316202757617.png)]

中間件:把很復雜的事情分割成單個,然后依次有條理的執行。就是一個中間處理環節,有輸入,有輸出。

說的通俗易懂點兒,中間件就是一個(從請求到響應調用的方法)方法。

把數據從請求到響應分步驟來處理,每一個步驟都是一個中間處理環節。

var http = require('http');
var url = require('url');var cookie = require('./expressPtoject/cookie');
var query = require('./expressPtoject/query');
var postBody = require('./expressPtoject/post-body');var server = http.createServer(function(){// 解析請求地址中的get參數// var obj = url.parse(req.url,true);// req.query = obj.query;query(req,res);	//中間件// 解析請求地址中的post參數req.body = {foo:'bar'}
});if(req.url === 'xxx'){// 處理請求...
}server.listen(3000,function(){console.log('3000 runing...');
});

同一個請求對象所經過的中間件都是同一個請求對象和響應對象。

var express = require('express');
var app = express();
app.get('/abc',function(req,res,next){// 同一個請求的req和res是一樣的,// 可以前面存儲下面調用console.log('/abc');// req.foo = 'bar';req.body = {name:'xiaoxiao',age:18}next();
});
app.get('/abc',function(req,res,next){// console.log(req.foo);console.log(req.body);console.log('/abc');
});
app.listen(3000, function() {console.log('app is running at port 3000.');
});

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qxpXgg9r-1588084625883)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200317110520098.png)]

中間件的分類:

應用程序級別的中間件

萬能匹配(不關心任何請求路徑和請求方法的中間件):

app.use(function(req,res,next){console.log('Time',Date.now());next();
});

關心請求路徑和請求方法的中間件:

app.use('/a',function(req,res,next){console.log('Time',Date.now());next();
});

路由級別的中間件

嚴格匹配請求路徑和請求方法的中間件

get:

app.get('/',function(req,res){res.send('get');
});

post:

app.post('/a',function(req,res){res.send('post');
});

put:

app.put('/user',function(req,res){res.send('put');
});

delete:

app.delete('/delete',function(req,res){res.send('delete');
});

var express = require('express');
var app = express();// 中間件:處理請求,本質就是個函數
// 在express中,對中間件有幾種分類// 1 不關心任何請求路徑和請求方法的中間件
// 也就是說任何請求都會進入這個中間件
// 中間件本身是一個方法,該方法接收三個參數
// Request 請求對象
// Response 響應對象
// next 下一個中間件
// // 全局匹配中間件
// app.use(function(req, res, next) {
// 	console.log('1');
// 	// 當一個請求進入中間件后
// 	// 如果需要請求另外一個方法則需要使用next()方法
// 	next();
// 	// next是一個方法,用來調用下一個中間件
//  // 注意:next()方法調用下一個方法的時候,也會匹配(不是調用緊挨著的哪一個)
// });
// app.use(function(req, res, next) {
// 	console.log('2');
// });// // 2 關心請求路徑的中間件
// // 以/xxx開頭的中間件
// app.use('/a',function(req, res, next) {
// 	console.log(req.url);
// });// 3 嚴格匹配請求方法和請求路徑的中間件
app.get('/',function(){console.log('/');
});
app.post('/a',function(){console.log('/a');
});app.listen(3000, function() {console.log('app is running at port 3000.');
});

錯誤處理中間件

app.use(function(err,req,res,next){console.error(err,stack);res.status(500).send('Something broke');
});

配置使用404中間件:

app.use(function(req,res){res.render('404.html');
});

配置全局錯誤處理中間件:

app.get('/a', function(req, res, next) {fs.readFile('.a/bc', funtion() {if (err) {// 當調用next()傳參后,則直接進入到全局錯誤處理中間件方法中// 當發生全局錯誤的時候,我們可以調用next傳遞錯誤對象// 然后被全局錯誤處理中間件匹配到并進行處理next(err);}})
});
//全局錯誤處理中間件
app.use(function(err,req,res,next){res.status(500).json({err_code:500,message:err.message});
});

內置中間件

  • express.static(提供靜態文件)
    • http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express

第三方中間件

參考文檔:http://expressjs.com/en/resources/middleware.html

  • body-parser
  • compression
  • cookie-parser
  • mogran
  • response-time
  • server-static
  • session

p.get(’/’,function(req,res){
res.send(‘get’);
});


post:```javascript
app.post('/a',function(req,res){res.send('post');
});

put:

app.put('/user',function(req,res){res.send('put');
});

delete:

app.delete('/delete',function(req,res){res.send('delete');
});

var express = require('express');
var app = express();// 中間件:處理請求,本質就是個函數
// 在express中,對中間件有幾種分類// 1 不關心任何請求路徑和請求方法的中間件
// 也就是說任何請求都會進入這個中間件
// 中間件本身是一個方法,該方法接收三個參數
// Request 請求對象
// Response 響應對象
// next 下一個中間件
// // 全局匹配中間件
// app.use(function(req, res, next) {
// 	console.log('1');
// 	// 當一個請求進入中間件后
// 	// 如果需要請求另外一個方法則需要使用next()方法
// 	next();
// 	// next是一個方法,用來調用下一個中間件
//  // 注意:next()方法調用下一個方法的時候,也會匹配(不是調用緊挨著的哪一個)
// });
// app.use(function(req, res, next) {
// 	console.log('2');
// });// // 2 關心請求路徑的中間件
// // 以/xxx開頭的中間件
// app.use('/a',function(req, res, next) {
// 	console.log(req.url);
// });// 3 嚴格匹配請求方法和請求路徑的中間件
app.get('/',function(){console.log('/');
});
app.post('/a',function(){console.log('/a');
});app.listen(3000, function() {console.log('app is running at port 3000.');
});

錯誤處理中間件

app.use(function(err,req,res,next){console.error(err,stack);res.status(500).send('Something broke');
});

配置使用404中間件:

app.use(function(req,res){res.render('404.html');
});

配置全局錯誤處理中間件:

app.get('/a', function(req, res, next) {fs.readFile('.a/bc', funtion() {if (err) {// 當調用next()傳參后,則直接進入到全局錯誤處理中間件方法中// 當發生全局錯誤的時候,我們可以調用next傳遞錯誤對象// 然后被全局錯誤處理中間件匹配到并進行處理next(err);}})
});
//全局錯誤處理中間件
app.use(function(err,req,res,next){res.status(500).json({err_code:500,message:err.message});
});

內置中間件

  • express.static(提供靜態文件)
    • http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express

第三方中間件

參考文檔:http://expressjs.com/en/resources/middleware.html

  • body-parser
  • compression
  • cookie-parser
  • mogran
  • response-time
  • server-static
  • session

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/248004.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/248004.shtml
英文地址,請注明出處:http://en.pswp.cn/news/248004.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

TCP/IP(六):HTTP 與 HTTPS 簡介

本文是準備面試過程中網絡部分總結整理的最后一篇文章&#xff0c;主要介紹以下知識&#xff1a; HTTP 協議概述POST 請求和 GET 請求Cookie 和 Session數據傳輸時的加密HTTPS 簡介 HTTP 協議 在 OSI 七層模型中&#xff0c;HTTP 協議位于最頂層的應用層中。通過瀏覽器訪問網…

Node — 第三天

模塊化 什么是模塊化 模塊化是指解決一個復雜問題時&#xff0c;自頂向下逐層把系統劃分成若干模塊的過程。 對于整個系統來說&#xff0c;模塊是可組合、分解和更換的單元。 生活中的模塊化 編程中的模塊化 編程領域中的模塊化&#xff0c;就是遵守固定的規則&#xff0c;…

FireDAC 中文字段過濾問題

當使用 FireDAC Filter 過濾數據的時候&#xff0c;通常這樣寫&#xff1a; FDMemTable.Filtered : False; FDMemTable1.Filter : 姓名 string(edtFilter.Text).QuotedString; FDMemTable.Filtered : True; 將會報錯&#xff1a;[FireDAC][Stan][Eval]-107. Invalid characte…

UIScrollViewDelegate-代理API詳解

在iOS編程中&#xff0c;經常用到UIScrollView控件。自然也會用到UIScrollViewDelegate協議。 今天就抽空&#xff0c;研究了一下UIScrollViewDelegate中所有的委托方法。 僅做Mark&#xff01;如有&#xff0c;錯誤之處&#xff0c;歡迎留言指正&#xff0c;交流&#xff01;貼…

License for package Android SDK Build-Tools 28.0.2 not accepted.(MAC)

https://blog.csdn.net/user11223344abc/article/details/83997907轉載于:https://www.cnblogs.com/dtdxrk/p/10812469.html

Express — 使用步驟

Express Express 介紹安裝搭建服務器的步驟express提供的新方法GET接口 獲取GET中的請求參數 POST接口 獲取POST請求提交的數據 中間件原理中間件語法中間件初體驗&#xff08;設置響應頭&#xff09;中間件開放靜態資源中間件接收POST請求體中間件返回404頁面 express 介紹 E…

大模型工具_Langchain-Chatchat

https://github.com/chatchat-space/Langchain-Chatchat 原Langchain-ChatGLM 1 功能 整體功能&#xff0c;想解決什么問題 基于 Langchain 與 ChatGLM 等LLM模型&#xff0c;搭建一套針對中文場景與開源模型&#xff0c;界面友好、可離線運行的知識庫問答解決方案。 當前解決…

iOS 鍵盤風格詳解UIKeyboardType

一、鍵盤風格 UIKit框架支持8種風格鍵盤。 [java] view plaincopy print?typedef enum { UIKeyboardTypeDefault, // 默認鍵盤&#xff1a;支持所有字符 UIKeyboardTypeASCIICapable, // 支持ASCII的默認鍵盤 UIKeyboardTypeNu…

MySQL Hardware--FIO壓測

FIO參數 filename/export/1.txt 支持文件系統或者裸設備&#xff0c;-filename/dev/sda2或-filename/dev/sdb direct1 測試過程繞過機器自帶的buffer&#xff0c;使測試結果更真實 rwrandwread 測試隨機讀的I/O rwrandwrite 測試隨機…

Node — 第四天(Promise與路由)

Promise - ES6新對象 Promise能夠處理異步程序。 回調地獄 JS中或node中&#xff0c;都大量的使用了回調函數進行異步操作&#xff0c;而異步操作什么時候返回結果是不可控的&#xff0c;如果我們希望幾個異步請求按照順序來執行&#xff0c;那么就需要將這些異步操作嵌套起來…

xcode8 升級后注釋快捷鍵不能使用的解決方法

一種說法&#xff1a; 這個是因為蘋果解決xcode ghost。把插件屏蔽了。解決方法 命令運行&#xff1a; sudo /usr/libexec/xpccachectl 然后必須重啟電腦后生效 還有一種說法&#xff1a;不用指令直接重啟就可以了。

winform datagridview控件使用

最近做項目時&#xff0c;顯示查詢結果總需要綁定到datagridview控件上顯示&#xff0c;總結了給datagridview綁定數據的方式&#xff0c;以及導出datagridview數據到excel表格&#xff0c;如有錯誤請多指教 1.直接綁定數據源&#xff0c;可以綁定的數據格式有List<T>,Da…

Node — 第五天

1. MySQL數據庫 phpstudy 數據庫服務器及圖形化軟件 軟件鏈接 鏈接&#xff1a;https://pan.baidu.com/s/1F8wdoMstHAJkINfDKDejsw 提取碼&#xff1a;xl3k 數據庫對于我們前端同學來說&#xff0c;就是一個了解。 對于不會變化的數據&#xff08;省、市、縣&#xff09;&…

iOS10 權限訪問崩潰

手機升級了 iOS10 Beta&#xff0c;然后用正在開發的項目 裝了個ipa包&#xff0c;發現點擊有關 權限訪問 直接Crash了&#xff0c;并在控制臺輸出了一些信息&#xff1a; This app has crashed because it attempted to access privacy-sensitive data without a usage descr…

Node — 第六天(前后端分離)及(身份驗證)

綜合應用服務端知識點搭建項目 下載安裝所需的第三方模塊 npm init -y npm i express cors mysql # express 用于搭建服務器 # cors 用于解決跨域 # mysql 用于操作數據庫# 后面用到什么&#xff0c;再下載創建app.js 之前&#xff0c;我們開啟一個服務器&#xff0c;js文件…

繼承上機作業

1、實現如下類之間的繼承關系&#xff0c;并編寫Music類來測試這些類 2、編寫一個Java應用程序&#xff0c;該程序包括3個類&#xff1a;Monkey類、People類和主類E。要求&#xff1a; (1) Monkey類中有個構造方法&#xff1a;Monkey (String s)&#xff0c;并且有個public voi…

ApplePay集成教程

Apple Pay運行環境&#xff1a;iPhone6以上設備&#xff0c;操作系統最低iOS9.0以上&#xff0c;部分信息設置需要iOS9.2以上。目前還不支持企業證書添加。 環境搭建好后可以在模擬器上面運行&#xff0c;xcode7.2.1iPhone6SP9.2系統下&#xff0c;系統會綁定幾種虛擬的銀行卡…

Node — 第七天 (大事件項目接口實現一)

關于JS錯誤處理 node中和mysql中的錯誤處理 node和MySQL提供的方法&#xff0c;已經對錯誤信息進行了封裝&#xff0c;只需要使用 err.message 即可獲取到錯誤信息。 比如&#xff1a; const fs require(fs); // 讀取一個不存在的文件 fs.readFile(abcd.txt, (err, data) …

1.Consul 簡介和環境搭建

1.什么是 Consul Consul 是 service mesh(服務網格)的一個解決方案&#xff0c;它提供了諸如服務發現&#xff0c;配置和隔離等功能的一整套控制平面(control plane)。開發人員可以根據需要單獨使用這些功能點&#xff0c;也可以將他們整合成為一個完整的service mesh。Consul …

Node — 第八天 (大事件項目接口實現二)

如何處理MySQL的錯誤 MySQL的錯誤信息&#xff0c;可以通過err來獲取。這是沒有問題的。 但是&#xff0c;我們加入了Promise&#xff0c;Promise中的錯誤&#xff0c;在外部是獲取不到的&#xff0c;只能使用Promise相關方法來獲取錯誤信息。 解決方法一 使用 JS原生的 tr…