天天看點

node Express 架構簡單介紹一下建立一個架構執行個體路由解析靜态檔案GET方法下面進行POST請求檔案上傳Cookie管理

node Express 架構

哈。github的位址已經更換,求start

https://github.com/mySoul8012

繼續~

Express架構

簡單介紹一下

Express事實上Node内置的http子產品上建構的一層抽象。理論上所有Express實作的功能都能用Node實作

核心特征;

  1. 設定中間件響應http請求
  2. 定義路由表,執行不同的http請求
  3. 先模闆傳遞參數,來動态的渲染html檔案

一些網址

npm的Express

https://www.npmjs.com/package/express

項目位址

https://github.com/expressjs/express

網址和文檔

http://expressjs.com/

翻譯的中文文檔

http://expressjs.com/zh-cn/

安裝Express

使用npm安裝,并将其儲存進入依賴清單中

由于一堵高不可攀的牆大人的問題,是以呢,被迫使用cnpm,使用來自淘寶的鏡像,由淘寶完成鏡像的同步

節省一點點寶貴的時間(^o^)/

全新安裝的需要安裝淘寶的鏡像 https://npm.taobao.org/

使用cnpm代替npm完成安裝

-save 的意思為自動更新依賴檔案,依賴檔案為package.json

PS C:\Users\mingm\Desktop\test\Express> cnpm install express --save
√ Installed 1 packages
√ Linked 46 latest versions
√ Run 0 scripts
Recently updated (since 2018-07-21): 1 packages (detail see file C:\Users\mingm\Desktop\test\Express\node_modules\.recently_updates.txt)
√ All packages installed (51 packages installed from npm registry, used 3s(network 3s), speed 291.62kB/s, json 47(354.74kB), tarball 535kB)
PS C:\Users\mingm\Desktop\test\Express>           

檢視依賴pacage.json檔案

{
  "dependencies": {
    "express": "^4.16.3"
  }
}
           

可以看到依賴的是express的4.16.3版本

檢視一下目錄

PS C:\Users\mingm\Desktop\test\Express> ls


    目錄: C:\Users\mingm\Desktop\test\Express


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        2018/7/28     18:35                node_modules
-a----        2018/7/28     18:35             53 package.json


PS C:\Users\mingm\Desktop\test\Express>           

可以檢視到有一個node_modules目錄,該目錄儲存的是npm包

一些還需要安裝的子產品

body-parser 一個node的中間件 用于處理JSON,等和URL的編碼的處理

https://www.npmjs.com/package/body-parser

文檔以及項目位址

https://github.com/expressjs/body-parser

cookie-parser 一個負責解析Cookie的工具可以将傳過來的Cookie将其轉換為對象

https://www.npmjs.com/package/cookie-parser

multer node.js的中間件 處理表單資料

https://github.com/expressjs/multer

npm

https://www.npmjs.com/package/multer

自訴檔案

https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md

原版的自述檔案

https://github.com/expressjs/multer/blob/master/README.md

好啦。一共是一塊安裝了3個子產品

繼續使用淘寶源

PS C:\Users\mingm\Desktop\test\Express> cnpm install body-parser --save
√ Installed 1 packages
√ Linked 0 latest versions
√ Run 0 scripts
√ All packages installed (used 248ms(network 242ms), speed 23.48kB/s, json 1(5.68kB), tarball 0B)
PS C:\Users\mingm\Desktop\test\Express> cnpm install cookie-parser --save
√ Installed 1 packages
√ Linked 0 latest versions
√ Run 0 scripts
√ All packages installed (used 264ms(network 258ms), speed 4.99kB/s, json 1(1.29kB), tarball 0B)
PS C:\Users\mingm\Desktop\test\Express> cnpm install multer --save
√ Installed 1 packages
√ Linked 21 latest versions
√ Run 0 scripts
√ All packages installed (22 packages installed from npm registry, used 1s(network 1s), speed 307.56kB/s, json 22(92.57kB), tarball 343.86kB)
PS C:\Users\mingm\Desktop\test\Express>           

完成三個子產品的安裝

檢視一下依賴檔案

{
  "dependencies": {
    "body-parser": "^1.18.3",
    "cookie-parser": "^1.4.3",
    "express": "^4.16.3",
    "multer": "^1.3.1"
  }
}
           

依賴四個子產品

建立一個架構執行個體

輸出hello world!

// app.js檔案
var express = require('express');
var app = express();

app.get('/', (req, res) => {
    res.send('hello world!');
});

var server = app.listen(1938, () => {
    var host = server.address().address;
    var port = server.address().port;

    console.log('%s:%s', host, port);
})           
PS C:\Users\mingm\Desktop\index\Express> node app.js
:::1938           

此程式會監聽1938上的連接配接,當有連接配接傳入的時候,應用程式會以hello world!進行響應,然後将其傳回。

路由

路由決定了由誰響應http請求,通過提取GET和POST請求的參數,下面繼續擴充程式

PS C:\Users\mingm\Desktop\index\Express> node app.js
{ address: '::', family: 'IPv6', port: 1937 }           
var express = require('express');
var app = express();

// 輸出hello world
app.get('/', (req, res) => {
    console.log('輸出對于首頁的GET請求');
    res.send('Hello GET!');
});

// post請求
app.post('/', (req, res) => {
    console.log('首頁post請求');
    res.send('Hello POST');
});

// 對于/del_user的頁面響應
app.get('/del_user', (req, res) => {
    console.log('這是對于頁面 /del_user頁面的響應');
    res.send("Hello del_user");
    res.send("你好哈! 這裡已經将頁面進行删除");
});

// /list_user 頁面的GET請求
app.get('/list_user', (req, res) => {
    console.log('這裡是對 /list_user頁面的請求');
    res.send('Hello list_user');
});

// /對頁面abcd abcdxcd ab123cd 的請求進去正則
app.get('ab*cd', (req, res) => {
    console.log('進行了正則');
    res.send('hello 正則!');
});

// 啟動http伺服器
var server = app.listen(1937, () => {
    console.log(server.address());
});           

通路

http://127.0.0.1:1937/del_user

傳回 Hello del_user

好啦!(^o^)/

解析靜态檔案

Express使用了中間件 express.static中間件設定靜态檔案

事實上是一個http伺服器外加一個fs子產品完成封裝的

目錄結構如下

- Express  // 站點檔案
    - image // 圖檔檔案夾
        1.gif   // 将要通路的靜态資源
    + node_modules  // npm包所在檔案夾
    app.js      // 入口檔案
    package.json    // 配置檔案           

代碼如下

PS C:\Users\mingm\Desktop\index\Express> node app.js
{ address: '::', family: 'IPv6', port: 1937 }
           
var express = require('express');
var app = express();

app.use(express.static('./image'));        // 使用中間件 express.static 設定的靜态資源檔案夾為image

app.get('/', (req, res) => {
    res.send('hello world!');
});

var server = app.listen(1937, () => {
    console.log(server.address());
});           
http://127.0.0.1:1937/1.gif

出現靜态資源,(^o^)/

GET方法

res.sendFile() http://expressjs.com/en/4x/api.html#res.sendFile

__dirname 擷取目前執行檔案所在目錄的完整目錄名

res.sendFlie(path [,options] [,fn]) path必須為絕對路徑,Content-Type 會根據擴充名設定相應的HTTP标頭字段,需要注意的是path必須為絕對路徑

__filename 擷取目前執行檔案帶有完整絕對路徑的檔案名

process.cwd() 擷取目前執行node指令時候的檔案夾的目錄名

./ 檔案所在目錄

req.query 此屬性是一個對象,包含路由中每個查詢字元串參數的屬性。

304請求 一個條件請求,如果有緩存的資料則進行請求,否則将不會進行請求

<!doctype html>
<html>
<head>
    <title>Hello from</title>
    <meta charset="utf-8">
</head>
<body>
    <form action="/process_get" method="get">
        <label>first_name</label><input type="text" name="first_name"/>
        <label>last_name</label><input type="text" name="last_name"/>
        <input type="submit" value="Submit"/>
    </form>
</body>
</html>           
var express = require('express');
var app = express();

app.use(express.static('public'));    // 加載中間件

app.get('/index.html', (req, res) => {    // 調用中間件指定的靜态資源目錄 public, 然後調用回調函數
    res.sendFile( __dirname + '/' + 'index.html');    // 輸出html檔案的絕對路徑,采取的是拼接字元串的方式,設定http标頭
});

app.get('/process_get', (req, res) => {
    // 輸出json格式
    var response = {
        'first_name': req.query.first_name,    // 将http封包中 查詢到的first_name的值作為屬性值
        'last_name': req.query.last_name    // 同上
    };
    console.log(response); // 輸出擷取到的json的值
    res.end(JSON.stringify(response));    // 将擷取到的值轉為JSON格式的值,然後進行傳回
});

var server = app.listen(1937, () => {
    console.log(server.address());
});           

用浏覽器檢視一下json資料

請求為get 發送的url為

http://127.0.0.1:1937/process_get?first_name=ming&last_name=ming

查詢的字元串為

first_name=ming

last_name=ming

總共,請求頭為

Host: 127.0.0.1:1937
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1:1937/
Cookie: hibext_instdsigdipv2=1
Connection: keep-alive
Upgrade-Insecure-Requests: 1           

主機位址為127.0.0.1:1937

user-Agent為本地的系統的一些資訊

剩下的有點看不懂。。╮(╯▽╰)╭

由于設定的是直接傳回JSON資料,是以檢視一下響應頭

{"first_name":"ming","last_name":"ming"}           

此為響應載荷

封包為

HTTP/1.1 200 OK
X-Powered-By: Express
Date: Sat, 28 Jul 2018 16:39:08 GMT
Connection: keep-alive
Content-Length: 40           

采用的是http1.1協定,傳回的封包為200

同理

DevTol也是如此不在進行闡述

下面進行POST請求

需要使用一個中間件 body-parser,其簡單的文檔 需要使用一個bodyParser.urlencoded 該對象傳回解析urlencoded主體。在傳回的body中,将會在req對象上添加一個新的對象,該對象為body。其中的值為字元串和數組,此對象會包含鍵值對。其中的值可以為字元串和數組(此時設定的extended的值為false),其中的值允許為任何類型的需要設定extended的值為last
var express = require('express');
var app = express();
var bodyParser = require('body-parser');    // 加載Express中間件

// 使用中間件提供的bodyParser.urlencoded對來自于post的url進行解析,隻允許字元串和數字類型的結果
var urlencodeParser = bodyParser.urlencoded({ extended: false });

app.use(express.static('public'));    // 設定靜态資源目錄為public

// 進行路由比對
app.get('/index.html', (req, res) => {
    res.sendFile(__dirname + '/' + 'index.html');    // 路徑的拼接,拼接的是目前檔案的所在目錄的絕對位址,由于要請求靜态資源,自動跳到public檔案夾下進行傳回
});

// post請求的比對
app.post('/process_post', urlencodeParser, (req, res) => {    // 先進行回調第一個函數,将post請求,使用中間件進行處理,處理完後的值進行傳回到req和res即下一個回調函數,資料經過兩次回調
    // 輸出JSON格式
    var response = {
        'first_name': req.body.first_name,    // 進行鍵值對的儲存
        'last_name': req.body.last_name    
    };
    console.log(response);    // 将接收到的資料進行輸出
    res.end(JSON.stringify(response));    // 将鍵值對儲存的對象轉化為JSON格式傳回給用戶端
});

var server = app.listen(1937, () => {    // 開啟http伺服器
    console.log(server.address());
});           
<!doctype html>
<html>
<head>
    <title>Hello from</title>
    <meta charset="utf-8">
</head>
<body>
    <form action="/process_post" method="POST">
        <label>first_name</label><input type="text" name="first_name"/>
        <label>last_name</label><input type="text" name="last_name"/>
        <input type="submit" value="Submit"/>
    </form>
</body>
</html>           

ok~

好啦。通路

http://127.0.0.1:1937

順便打開浏覽器開發者工具進行檢視傳回的JSON資料

{"first_name":"ming","last_name":"ming"}           

(^∇^*)完美~

檔案上傳

使用post方法完成檔案的上傳。

from 表單的enctype屬性當method屬性值為post的時候,enctype送出的是from給伺服器内容的mime類型,即媒體類型,

解釋一下form表單的enctype的三個值

http的post方法,給伺服器時,請求主題類型由 Content-Type 指定,通常一個POST請求是通過HTML表單發送的,并傳回給伺服器傳回修改的結果,form表單的enctype屬性是設定上傳的編碼的

application/x-www-form-urlencoded 資料被編碼成為&進行分割的鍵值對同時以=作為分割的鍵值對。非字母和數字的字元會被進行百分比編碼 解釋

https://developer.mozilla.org/zh-CN/docs/Glossary/percent-encoding

multipart/form-data 将會以二進制的方式進行上傳,上傳檔案的時候必須按照這個方法進行送出

text/plain 空格轉化為+号,不對其做任何的處理進行送出

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POST

multer(opts) opts具有一個dest屬性,将會告訴Multer中間件上傳到伺服器的位置。

multer(opts)接受鍊式調用.array(fieldname[, maxCount]) 支援一個是否為檔案數組

/*
var express = require('express');
var app = express();    // 建立架構的類
var fs = require('fs');

var bodyParser = require('body-parser');    // 加載中間件
var multer = require('multer');
var storage = multer.diskStorage({ 
    destination: (req, file, cb) => {
        cb(null, './image')    // 檔案上傳的目錄
    },
    filename: (req, file, cb) => {
        var fileFormat = (file.originalname).split(".");    // 先将檔案名采用split按照.進行分裂
        cb(null, file.fieldname + '-' + Date.now() + '.' +  fileFormat[fileFormat.length - 1]);    // 對檔案重命名,加上擴充名
    }
});    // 确定一下上傳的配置選項


app.use(express.static('public'));    // 添加靜态檔案,用于處理靜态檔案,架構自帶的
app.use(bodyParser.urlencoded({ extended: false }));    // 用于處理JSON等資料
app.use(multer({storage: storage}).array('image'));

app.get('/index.html', (req, res) => {
    res.sendFile( __dirname + '/' + 'index.html' );    // 對于首頁的請求
});

// 該過程中間經曆了對靜态檔案的(static中間件,urlencoded對url的解析,隻允許字元串和數字的結果,使用了上傳的multer的中間件,最後到回調函數)
app.post('/file_upload', (req, res) => {    // 允許上傳多個檔案,其中檔案數組儲存在req.files
    console.log(req.files[0]);    // 上傳檔案的資訊
     var des_file = __dirname + "/" + req.files[0].originalname;
   fs.readFile( req.files[0].path, function (err, data) {
        fs.writeFile(des_file, data, function (err) {
         if( err ){
              console.log( err );
         }else{
               response = {
                   message:'File uploaded successfully', 
                   filename:req.files[0].originalname
              };
          }
          console.log( response );
          res.end( JSON.stringify( response ) );
       });
   });
});

var server = app.listen(1937, () => {
    console.log(server.address());
});



*/

var express = require('express');
var app = express();
var fs = require("fs");
 
var bodyParser = require('body-parser');
var multer  = require('multer');
 
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));    // 設定臨時上傳的位址
 
app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})
 
app.post('/file_upload', function (req, res) {
 
   console.log(req.files[0]);  // 上傳的檔案資訊
 
   var fileFormat = (req.files[0].originalname).split(".");
   var fileName = req.files[0].fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1];
   var des_file = __dirname + "/image/" + fileName;    // 将要上傳的位址

    console.log(des_file);
    fs.open( './image/' + fileName, 'a', function(err, fd) {
   if (err) {
       return console.error(err);
   }
  fs.readFile( req.files[0].path, (err, data) => {
            fs.writeFile(des_file, data, (err) => {
            console.log(data);
             if( err ){
                  console.log( err );
             }else{
                   response = {
                       message:'File uploaded successfully', 
                       filename:req.files[0].originalname
                  };
              }
              console.log( response );
              res.end( JSON.stringify( response ) );
               });
           });    
});

          
});
 
var server = app.listen(8081, function () {
 
  var host = server.address().address
  var port = server.address().port
 
  console.log("應用執行個體,通路位址為 http://%s:%s", host, port)
 
})
           

思路,是先将檔案以追加的方式打開,然後将通過中間件上傳的檔案寫入追加打開的檔案

<html>
<head>
    <title>檔案上傳表單</title>
</head>
<body>
    <h3>檔案上傳</h3>
    <form action="/file_upload" method="post" enctype="multipart/form-data">
        <input type="file" name="image" size="50">
        <br>
        <input type="submit" value="上傳檔案">
    </form>
</body>
</html>           

Cookie管理

使用中間件發送Cokie資訊。

引入cookie-parser

再引入 util子產品,将對象轉換為字元串

這個很簡單。過