node Express 架構
哈。github的位址已經更換,求start
https://github.com/mySoul8012繼續~
Express架構
簡單介紹一下
Express事實上Node内置的http子產品上建構的一層抽象。理論上所有Express實作的功能都能用Node實作
核心特征;
- 設定中間件響應http請求
- 定義路由表,執行不同的http請求
- 先模闆傳遞參數,來動态的渲染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-parsercookie-parser 一個負責解析Cookie的工具可以将傳過來的Cookie将其轉換為對象
https://www.npmjs.com/package/cookie-parsermulter node.js的中間件 處理表單資料
https://github.com/expressjs/multernpm
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-encodingmultipart/form-data 将會以二進制的方式進行上傳,上傳檔案的時候必須按照這個方法進行送出
text/plain 空格轉化為+号,不對其做任何的處理進行送出
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Methods/POSTmulter(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子產品,将對象轉換為字元串
這個很簡單。過