Node express 框架


簡介

Express 是基於 Node.js 平台,快速、開放、極簡的 Web 開發框架, 提供一系列強大特性幫助你創建各種Web應用。Express 不對 node.js 已有的特性進行二次抽象,我們只是在它之上擴展了Web應用所需的功能。豐富的HTTP工具以及來自Connect框架的中間件隨取隨用,創建強健、友好的API變得快速又簡單

官網

https://www.expressjs.com.cn/

安裝

首先假定你已經安裝了 Node.js,接下來為你的應用創建一個目錄,然后進入此目錄並將其作為當前工作目錄。

通過 npm init 命令為你的應用創建一個 package.json 文件。 欲了解 package.json 是如何起作用的,請參考 Specifics of npm’s package.json handling.

$ npm init

此命令將要求你輸入幾個參數,例如此應用的名稱和版本。 你可以直接按“回車”鍵接受大部分默認設置即可,下面這個除外:

entry point: (index.js)

鍵入 app.js 或者你所希望的名稱,這是當前應用的入口文件。如果你希望采用默認的 index.js 文件名,只需按“回車”鍵即可。

image-20201006143242280

接下來在 myapp 目錄下安裝 Express 並將其保存到依賴列表中。如下:

$ npm install express --save

image-20201006143328300

如果只是臨時安裝 Express,不想將它添加到依賴列表中,可執行如下命令:

$ npm install express --no-save

npm 5.0+ 版本在默認情況下會將安裝的模塊添加到 package.json 文件中的 dependencies 列表中。對於較老的 npm 版本,你就必須指定 --save 參數。然后,照舊執行 npm install 命令即可自動安裝依賴列表中所列出的所有模塊。

hello world

創建app.js 並寫入

const express = require('express');
const app = express();
const port = 3000;

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

app.listen(port, function(){
    console.log(`請求訪問127.0.0.1:${port}!`)
});

運行結果

image-20201006144242479

到此簡單的hello world 已經完成

使用

內置路由和外置路由

內置路由和外置路由簡單理解就是把路由寫在app.js(入口文件)文件中,還是寫在其他文件中,寫在app.js文件里就是內置路由其他文件就是外置路由。如上面的hello world案例就是內置路由,不過一般都是使用外置路由。

route.js

//引入express 框架模塊
var express = require('express');
//獲取路由對象
var router = express.Router();

//設置路由
router.get('/',(req,res)=>{
    res.send('123');
})
router.get('/user',(req,res)=>{
    res.send('user');
})
router.post('/edit',(req,res)=>{
    res.send('post_edit');
})

// 導出 路由router
module.exports = router;

app.js

var express = require('express');
var app = express();

// 引入外置路由模塊
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

運行結果

image-20201006150209015

使用art-template模板引擎

art-template@4 新特性

express-art-template

在express框架中使用art-template模板引擎還需要安裝express-art-template

安裝

npm install --save art-template
npm install --save express-art-template

官方示例:

var express = require('express');
var app = express();
app.engine('art', require('express-art-template'));
app.set('view options', {
    debug: process.env.NODE_ENV !== 'production'
});

app.get('/', function (req, res) {
    res.render('index.art', {
        user: {
            name: 'aui',
            tags: ['art', 'template', 'nodejs']
        }
    });
});

Demo

app.js

var express = require('express');
var app = express();

//注冊引擎
app.engine('html', require('express-art-template'));

// 引入外置路由模塊
var rout = require('./route');
// 使用引入外置的路由
app.use(rout);

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

route.js

//引入express 框架模塊
var express = require('express');
//獲取路由對象
var router = express.Router();

//設置路由
router.get('/',(req,res)=>{
    //默認會去當前目錄下的views目錄下獲取靜態頁面
    res.render('index.html', {title:'express-art-template-title'});
})

// 導出 路由router
module.exports = router;

./views/index.html

<h1>{{title}}</h1>

運行結果

image-20201006154222880

遇到的問題

模板路徑的問題

image-20201006154422980

在項目中新建views目錄,將所有靜態頁面放入views目錄

image-20201006154501412

響應html頁面

之前使用http模塊的時候,是用fs讀取html文件內容並且設置響應頭才可以響應html頁面,比較麻煩。那么現在express框架有什么比較簡單的辦法呢?

API

res.sendFile(路徑[,選項] [,fn])

res.sendFile() Express v4.8.0及更高版本受支持。

在給定的位置傳輸文件pathContent-Type根據文件名的擴展名設置響應HTTP標頭字段。除非root在選項對象中設置了選項,path否則必須是文件的絕對路徑

該API提供對正在運行的文件系統上的數據的訪問。確保(a)如果path參數包含用戶輸入,則將參數構造為絕對路徑的方法是安全的;或者(b)將root選項設置為包含訪問權限的目錄的絕對路徑。

root被提供的選項,所述path參數被允許是相對路徑,包括含有..。Express將驗證提供的相對路徑path是否可以在給定的root選項內解析。

下表提供了有關該options參數的詳細信息。

屬性 描述 默認 可用性
maxAge Cache-Control以毫秒為單位設置標頭的max-age屬性,或以ms格式設置字符串 0
root 相對文件名的根目錄。
lastModified Last-Modified標頭設置為操作系統上文件的最后修改日期。設置false為禁用它。 已啟用 4.9.0+
headers 包含要與文件一起使用的HTTP標頭的對象。
dotfiles 用於提供點文件的選項。可能的值為“允許”,“拒絕”,“忽略”。 “忽視”
acceptRanges 啟用或禁用接受遠程請求。 true 4.14+
cacheControl 啟用或禁用設置Cache-Control響應頭。 true 4.14+
immutable immutableCache-Control響應頭中啟用或禁用指令。如果啟用,maxAge還應指定該選項以啟用緩存。該immutable指令將阻止受支持的客戶端在maxAge選項的有效期內提出條件請求,以檢查文件是否已更改。 false 4.16+

fn(err)傳輸完成或發生錯誤時,該方法將調用回調函數。如果指定了回調函數並且發生錯誤,則回調函數必須通過結束請求-響應周期或將控制權傳遞給下一條路由來顯式處理響應過程。

注意:上面寫了除非設置了root選項,否則文件路徑必須是絕對路徑

這時候就要使用__dirname這個,來獲取當前目錄的絕對路徑了

文檔:http://nodejs.cn/api/modules/dirname.html

響應html頁面的Demo

route.js

//引入express 框架模塊
var express = require('express');
//獲取路由對象
var router = express.Router();

//設置路由
router.get('/',(req,res)=>{
   //只能絕對路徑
   res.sendFile(__dirname+'/views/index.html');
})

// 導出 路由router
module.exports = router;

利用 Express 托管靜態文件

官方文檔:http://www.expressjs.com.cn/starter/static-files.html

為了提供諸如圖像、CSS 文件和 JavaScript 文件之類的靜態文件,請使用 Express 中的 express.static內置中間件函數。

此函數特征如下:

express.static(root, [options])

The root argument specifies the root directory from which to serve static assets. For more information on the options argument, see express.static.

例如,通過如下代碼就可以將 public 目錄下的圖片、CSS 文件、JavaScript 文件對外開放訪問了:

app.use(express.static('public'))

現在,你就可以訪問 public 目錄中的所有文件了:

http://localhost:3000/images/kitten.jpg
http://localhost:3000/css/style.css
http://localhost:3000/js/app.js
http://localhost:3000/images/bg.png
http://localhost:3000/hello.html

Express 在靜態目錄查找文件,因此,存放靜態文件的目錄名不會出現在 URL 中。

如果要使用多個靜態資源目錄,請多次調用 express.static 函數:

app.use(express.static('public'))
app.use(express.static('files'))

訪問靜態資源文件時,express.static 函數會根據目錄的添加順序查找所需的文件。

Demo

1.新建靜態資源存放路徑,如public

image-20201006155903524

2.入口文件中設置靜態資源目錄

app.use(express.static('public'))

就可以了

例:

app.js

var express = require('express');
var app = express();

//設置靜態資源目錄
app.use(express.static('public'))

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

./public/img/test.jpg

image-20201006162515399

訪問http://127.0.0.1:8000/img/test.jpg

image-20201006162628006

如果是在其他靜態頁面中使用則直接寫

<img src="/img/test.jpg">

直接寫相對於public 的目錄下的路徑即可

使用formidable進行文件上傳

npm地址:https://www.npmjs.com/package/formidable

安裝

npm install formidable

選項

  • options.encoding {string} -默認值'utf-8';設置傳入表單字段的編碼,
  • options.uploadDir {string} -默認值os.tmpdir();用於放置文件上載的目錄。稍后可以使用進行移動fs.rename()
  • options.keepExtensions {boolean} -默認值false;是否包含原始文件的擴展名
  • options.maxFileSize {number} -默認值200 * 1024 * 1024(200mb);限制上傳文件的大小。
  • options.maxFields {number} -默認值1000;限制Querystring解析器將解碼的字段數,將0設置為無限制
  • options.maxFieldsSize {number} -默認值20 * 1024 * 1024(20mb);限制所有字段(文件除外)可一起分配的內存量(以字節為單位)。
  • options.hash {boolean} -默認值false;包括為傳入文件計算的校驗和,將其設置為某種哈希算法, 有關可用算法,請參見 crypto.createHash
  • options.multiples {boolean} -默認值false;當您調用該 .parse方法時,files(回調的)參數將包含用於輸入的文件數組,這些輸入使用HTML5multiple 屬性提交多個文件。同樣,該fields參數將包含名稱以“ []”結尾的字段的值數組。

普通表單控件和文件表單控件數據結構示例

普通表單控件

{ name: 'zhangsan' }

image-20201006172128158

文件表單控件

{
  file: File {
    _events: [Object: null prototype] {},
    _eventsCount: 0,
    _maxListeners: undefined,
    //文件大小
    size: 57313,
    //文件路徑
    path: 'public\\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
    //文件名
    name: 'u=313355857,739398057&fm=26&gp=0.jpg',
    //文件類型
    type: 'image/jpeg',
    hash: null,
    //最后修改時間
    lastModifiedDate: 2020-10-06T09:17:13.572Z,
    _writeStream: WriteStream {
      _writableState: [WritableState],
      _events: [Object: null prototype] {},
      _eventsCount: 0,
      _maxListeners: undefined,
      path: 'public\\upload_aa5dfaec37e92b4efe60ae1cec4d6f2d.jpg',
      fd: 3,
      flags: 'w',
      mode: 438,
      start: undefined,
      autoClose: true,
      pos: undefined,
      bytesWritten: 57313,
      closed: false,
      [Symbol(kFs)]: [Object],
      [Symbol(kCapture)]: false,
      [Symbol(kIsPerformingIO)]: false
    },
    [Symbol(kCapture)]: false
  }
}

image-20201006172237589

Demo

var express = require('express');
var fs = require('fs');
var formidable = require('formidable');
var app = express();

app.post('/upload',(req,res)=>{
    //創建上傳表單
    var form = new formidable.IncomingForm();

    //設置
    //formidable的默認保存路徑是:“C:\Users\Administrator\AppData\Local\Temp”
    //修改formidable 臨時存放存儲路徑為當前目錄下的public
    form.uploadDir = './public';
    // 保留文件擴展名
    form.keepExtensions = true;

    /**
     * err 表示錯誤信息
     * fields 表示普通表單控件
     * files 表示文件表單控件
     */
    form.parse(req, function (err, fields, files) {
        console.log(fields);
        console.log(files);

        var times = new Date().getTime();
        // 組裝上傳路徑
        var file_path = './public/'+times+files.file.name;
        // 將緩存文件移動至制定目錄
        fs.rename(files.file.path,file_path,(err)=>{
            console.log(file_path);
        });
        res.end();
    });
})
app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

運行結果

image-20201006171956784

使用cookie與session

express官方資源中,為我們提供了一個中間件,cookie-session

安裝

npm install cookie-session

Demo

var express = require('express');
var cookieSession = require('cookie-session')
var app = express();

// 注冊中間件
app.use(cookieSession({
    name: 'session', // 客戶端cookie的名稱
    keys: ['ss'] // 用於加密的關鍵字
}))

app.get('/', (req, res) => {
    // 獲取並判斷session
    if(req.session.sess_data){
        res.send('已經登陸')
    }else{
        // 如果沒有session,跳轉到登陸頁面
        res.send('<script>alert("沒登陸");window.location.href="/up"</script>');
    }
})
app.get('/up', (req, res) => {
    // 展示登陸頁面,獲取用戶數據並寫入session
    req.session.sess_data = {name:12,age:89};
    res.send('已寫入session');
});

app.listen('8000',()=>{
    console.log('127.0.0.1:8000')
})

這個Demo第一次訪問如果沒session 會在彈框之后自動寫入session

image-20201007140500022

再次訪問

image-20201007140525761

Express的中間件

什么是中間件

在一個整體的流程中的某個環節,因為某些原因加入了額外的處理環節;

中間件的使用

應用中間件

語法:

  • app.use()

    • app.use(function(){})

      無論發送任何請求都會執行的中間件

    • app.use('/path', function(){})

      只要在請求path路由時才會執行的中間件(無論GET/POST)

  • app.method()

    • app.get()

      在get請求時會執行的中間件

    • app.post()

      在post請求時會執行的中間件

app.use() 的用法

var express = require('express');
var app = express();

// 在中間件之前,不受中間件影響
app.get('/',function(req,res){
    console.log(123);
})

// 應用中間件
//表示匹配任何路由
// 請求 '/user' 時,會先調用中間件
app.use(function (req, res, next) {
    console.log(req);
    next();
});

// 調用之前先調用中間件
app.get('/user',function(req,res){
    console.log('user');
})

app.listen('8000', () => {
    console.log('127.0.0.1:8000')
})

app.method() 的用法

var express = require('express');
var app = express();

// 在中間件之前,不受中間件影響
app.get('/',function(req,res){
    console.log(123);
})

// 應用中間件,也叫路由中間件
// 只有在 post 請求user 時才起作用
app.post('/user',function (req, res, next) {
    console.log(req);
    //表示匹配完成這個中間件就繼續往下執行。
    next();
});

// 調用之前先調用中間件
// 接受所有請求方式請求user
app.all('/user',function(req,res){
    console.log('user');
})

app.listen('8000', () => {
    console.log('127.0.0.1:8000')
})

路由中間件

路由器層中間件的工作方式與應用層中間件基本相同,差異之處在於它綁定到 express.Router() 的實例。

使用 router.use()router.METHOD() 函數裝入路由器層中間件;

例:

var app = express();
var router = express.Router();

//沒有掛載路徑的中間件。這段代碼對每個發送到路由器的請求都執行
router.use(function (req, res, next) {
  console.log('Time:', Date.now());
  next();
});

//中間件子堆棧向/user/:id路徑顯示任何類型的HTTP請求的請求信息
router.use('/user/:id', function(req, res, next) {
  console.log('Request URL:', req.originalUrl);
  next();
}, function (req, res, next) {
  console.log('Request Type:', req.method);
  next();
});

// 處理/user/:id路徑的GET請求的中間件子堆棧
router.get('/user/:id', function (req, res, next) {
  // 如果用戶ID為0,則跳到下一個路由器
  if (req.params.id == 0) next('route');
  // 否則,將控制權傳遞給該堆棧中的下一個中間件函數
  else next(); //
}, function (req, res, next) {
  // 呈現常規頁面
  res.render('regular');
});

// 用於/user/:id路徑的處理程序,它將呈現一個特殊的頁面
router.get('/user/:id', function (req, res, next) {
  console.log(req.params.id);
  res.render('special');
});

// 使用路由
app.use('/', router);

內置中間件

express.static 外,先前 Express 隨附的所有中間件函數現在以單獨模塊的形式提供:中間件函數的列表

Express 中唯一內置的中間件函數是 express.static。此函數基於 serve-static,負責提供 Express 應用程序的靜態資源。

對於每個應用程序,可以有多個靜態目錄:

app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));

第三方中間件

使用第三方中間件向 Express 應用程序添加功能。

安裝具有所需功能的 Node.js 模塊,然后在應用層或路由器層的應用程序中將其加裝入。

var cookieSession = require('cookie-session');

// 注冊中間件 
app.use(cookieSession({
    name: 'session', // 客戶端cookie的名稱
    keys: ['xilingzuishuai'] // 用於加密的關鍵字
}))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM