文章目錄
-
- 前言
- 1 Express
-
- 1.1 什麼是express
- 1.2 為什麼需要express
- 1.3 手動安裝手動配置
- 2 Express基本使用
-
- 2.1 主要代碼及注釋
- 3 處理網頁
-
- 3.1 處理靜态資源
- 3.2 什麼是ejs(模闆引擎)
-
- 3.2.1 ejs的特點
- 3.2.2 ejs的成員函數
- 3.3.3 ejs的常用标簽
- 3.3 處理動态資源
- 在模闆中使用資料
- 4 處理路由
-
- 4.1 應用級别中路由
- 4.2 處理路由第二種方式
- 5 會話技術
-
- 5.1 什麼是會話?
- 5.2 會話技術
- 5.3 cookie作用
- 5.4 cookie記錄上一次通路的時間
- 5.5 session的使用
- 6 Express中間件
-
- 6.1 next介紹
- 6.2 next使用
- 6.3 next正确使用方式
- 6.4 express中間件
- 7 Express腳手架
-
- 7.1 通過express搭建項目
- 7.2 生成的app.js
前言
這部分主要是node使用express架構之後的簡寫版本。
1 Express
express:表達;快速(這裡取快速的翻譯)
1.1 什麼是express
Express是一個基于NodeJS的Web Server開發架構, 能夠幫助我們快速的搭建Web伺服器。
1.2 為什麼需要express
-
利用原生的NodeJS開發Web伺服器,
我們需要處理很多繁瑣且沒有技術含量的内容。
例如: 擷取路由->解析路由->配置設定路由->處理路由等。
但是有了Express之後, 就能幫助我們省去大量繁瑣的環節, 讓我們隻用關注核心業務邏輯。
-
利用原生的NodeJS開發Web伺服器,
我們需要自己手動去實作靜态/動态資源處理, get/post參數的解析, cookie的解析, 日志處理等。
但是有了Express之後, 已經有現成的插件幫我們實作了上述功能。
- 是以作為單身的程式猿(媛), 如果你還想留一些時間去約會, 那麼Express是你的最佳選擇。
1.3 手動安裝手動配置
傳送門
安裝:
npm i express -S
2 Express基本使用
2.1 主要代碼及注釋
// 導入express
const express = require("express");
// express執行(調用express方法),建立服務端執行個體對象
const app = express();
// req,res 并不是原生node中的req,res
// 它是在原生node的基本上進行增強
// 雖然此處req,res進行了增強,但是也可以使用原生node中的api
app.get("/",(req,res)=>{//路由 預設是/ 一個位址,對應了一個響應
// res.writeHead(200,{'Content-type':'text/plain;charset=utf-8'})//解決字元亂碼問題
// res.end("www.badu.com")//響應資料
//之前的原生方法也能使用
res.send("hello express")
})
app.get("/login",(req,res)=>{ // 一個位址,對應了一個響應
res.send("<h1>登入頁面</h1>")
})
//監聽端口
app.listen(3000,()=>{//告訴服務端需要監聽哪一個端口
console.log("server is running on 3000");
})
res.send([body|status], [body])
既可以直接發送内容,也可以第一個參數狀态,第二個參數内容。
如果直接發送内容的話,狀态會被自動補全;
詳細介紹:傳送門
我們向伺服器發一個請求,核心有兩種請求方式:
1)get請求 偏向于向伺服器要資料 當然也可以把資料給伺服器
A)浏覽器的位址欄就可以發起get請求
B)a标簽的href也可以發起get請求
C)link标簽的href也可以發起get請求
D)script 标簽的 src也可以發起get請求
E)img标簽的src也可以發起get請求
F)form表示也可以發起Get表示
…
特點:
1)會資料放到位址欄中 不太安全
2)post請求 偏向于把資料扔給伺服器
利用form表示發起get請求:
1)action表示此請求位址
2)method請求的方式
3)表單中的input必須要有一個name屬性
<form action="http://localhost:3333/doreg" method="get">
<ul>
<li>使用者名:<input type="text" name="username"></li>
<li>密碼:<input type="password" name="pwd"></li>
<li><input type="submit" value="注冊"></li>
</ul>
</form>
3 處理網頁
3.1 處理靜态資源
const express = require("express");
const path = require("path")
const app = express();
//可以配置多個靜态資源目錄
app.use(express.static('public'))
// app.use(express.static('files'))
// app.use('/static', express.static('files'))
========================express托管靜态資源
// use 表示使用中間件 express内部自帶一個中間件 express.static()
// express.static 此中間件就可以托管靜态資源 是一個内置的中間件
// console.log(path.join(__dirname,"public"));
app.use(express.static(path.join(__dirname, 'public')));
項目位置:
3.2 什麼是ejs(模闆引擎)
ejs
:一個模闆引擎,預設情況下,你的模闆中寫的資料都是假資料,一般資料都是來自于資料庫的。如果把資料庫中的資料取出來,放到需要
替換資料
的地方,此時就是一個真資料,這個流程叫
服務端渲染
。
3.2.1 ejs的特點
- 快速編譯和渲染
- 簡單的模闆标簽
- 自定義标記分隔符
- 支援文本包含
- 支援浏覽器端和伺服器端
- 模闆靜态緩存
- 支援express視圖系統
3.2.2 ejs的成員函數
Render(str,data,[option]):直接渲染字元串并生成html
str:需要解析的字元串模闆
data:資料
option:配置選項
3.3.3 ejs的常用标簽
<% %>流程控制标簽
<%= %>輸出标簽(原文輸出HTML标簽)
<%- %>輸出标簽(HTML會被浏覽器解析)
<%# %>注釋标簽
% 對标記進行轉義
3.3 處理動态資源
模闆:就是前端程式員寫好的html頁面,html頁面中的資料預設都是假資料,我們需要把它裡面的假資料替換成真實的資料,此時就需要使用模闆。一般情況下,是把模闆放在views下面的,如下:
原本是
.html
需要換為
.ejs
,也可以用别的方法代替。
在模闆中使用資料
var ejs = require("ejs");// 導入ejs子產品
==================================路徑寫法一
app.use(express.static(path.join(__dirname,"public")))
// 1)告訴express,你的模闆在什麼地方
app.set("views",path.join(__dirname,"views"));//絕對路徑的寫法
==================================路徑寫法二
// 把./views目錄設定為模闆檔案根,html檔案模闆放在view目錄中
app.set("views", "./views");//告訴express,模闆放在views下面
==============================================================================
// 設定模闆引擎為ejs
// 2)告訴express,你使用的模闆引擎是什麼 ejs 除了ejs模闆引擎之外,還有其它的模闆引擎
app.set('view engine', 'ejs')
app.get("/xxx",(req,res)=>{
// res.send("hello express")
// 把資料渲染到模闆中 通過res.render就可以渲染模闆,同時就可以給模闆上綁定資料
res.render('xxx',{msg:"dadaima"});
})
<h1>我是一個模闆</h1>
<h2><%= msg %></h2>
4 處理路由
4.1 應用級别中路由
const express = require("express");
// app叫應用
const app = express();
app.get("/reg", (req, res) => {
res.send("<h1>注冊頁面</h1>")
})
app.get("/login", (req, res) => {
res.send("<h1>登入頁面</h1>")
})
app.get("/cart", (req, res) => {
res.send("<h1>購物車頁面</h1>")
})
app.post('/api/user/register', (req, res, next) => {
res.json({
name: 'xq',
age: 18,
method: 'post'
});
});
app.listen(3000, () => {
console.log("server is running on 3000");
})
注意:
1.響應對象的json方法是express給響應對象擴充的
2.這個方法會自動将對象轉換成字元串之後傳回
3.這個方法還會自動幫助我們設定響應頭
4.2 處理路由第二種方式
在項目的根目錄下,建立一個routes檔案夾:
不同的子產品,有不同的路由檔案,這裡的
routes
和controller的意思是一樣的。
user.js
和
goods.js
裡面的路由,叫
二級路由
。
user.js代碼如下:
const express = require("express");
// router叫路由對象
const router = express.Router();
// 說白了,就是我們前面講的controller
// 二級路由
router.get("/login", (req, res, next) => {
res.send("<h1>登入頁面</h1>")
})
router.get("/reg", (req, res, next) => {
res.send("<h1>注冊頁面</h1>")
})
// 導出路由對象
module.exports = router;
goodes.js類似user.js
。
在入口檔案引入獨立的子產品
// app.js
const express = require("express");
// 引入二級路由檔案
const userRouter = require("./routes/user")
const goodsRouter = require("./routes/goods")
const app = express();
// 一級路由 當通路/api/user時,就把這個路由交給userRouter來處理
app.use("/api/user", userRouter)
app.use("/api/goods", goodsRouter)
app.listen(3000, () => {
console.log("server is running on 3000");
})
5 會話技術
Cookie:浏覽器端的會話技術。
Session:伺服器端的會話技術。
5.1 什麼是會話?
日常生活中:從撥通電話到挂斷電話之間的一連串你問我答的過程就是一個會話。
B/S架構中:從浏覽器第一次給伺服器發送請求時,建立會話;直到有一方斷開,會話結束。
一次會話:包含多次請求響應。
5.2 會話技術
問題:Http是一個無狀态協定,同一個會話的連續兩個請求互相獨立,彼此并不了解。
會話技術能彌補http協定無狀态帶來的麻煩。
作用:用于存儲浏覽器與伺服器在請求和響應過程中産生的資料
在一次會話中(多次請求響應), 共享資料
用戶端會話技術:
cookie
伺服器端會話技術:
session
5.3 cookie作用
Cookie作用:在一次會話的多次請求之間共享資料,将資料儲存到
用戶端(浏覽器)
。
伺服器可以給用戶端種植一個cookie:
cookie: 小甜點 餅幹 cookie本質就是存儲資料的
伺服器給用戶端種植了一個cookie,那麼這個cookie就存儲在用戶端。
一旦種植了,後面每一次請求,都會帶上這個cookie。
伺服器給用戶端種植了一個cookie,cookie儲存在什麼地方?
答:在開發者工具中,找到application,在左側找到cookie選項,伺服器種植的cookie就存在在這個地方。
ookie的特點:
- cookie儲存在用戶端(浏覽器), 往往是由伺服器産生發送給浏覽器
- cookie隻能儲存字元串, 格式是entry(name : value)
- cookie的大小有限制: 4k
- 一般, 同一域名下的cookie限制數量50個
使用:(需要子產品:
npm i cookie-parser
)
const express = require("express")
const path = require("path")
const cookieParser = require('cookie-parser')
let app = express();
app.use(express.static(path.join(__dirname,'public')))
// 配置cookie
app.use(cookieParser())
app.get("/",(req,res)=>{
// 需要在服務端種植一個cookie,種到了浏覽器的時面
// 後面,每一次請求,浏覽器都會帶上這個cookie
// 給用戶端種植一個cookie
// res.cookie("usrename","wangcai"); // 預設情況下,會話結束,cookie就死了
// 活7天 設定cookie的生存時間
// res.cookie("username","wc",{maxAge:60000*60*24*7})
// 擷取浏覽器帶過來的cookie
console.log("擷取cookie:",req.cookies);
res.send("hello 用戶端~")
})
app.listen(3000,()=>{
console.log("server is running 3000~");
})
總結:
預設cookie的生存時間:
種植:res.cookie("username","wangcai");
當浏覽器關閉後,cookie就沒了,這個過程,叫一次會話。預設情況下,會話結束了,cookie就沒有了。
第一次,會種植一個cookie,後面再次去請求伺服器時,它會把cookie攜帶上。
使用cookie的缺點:
1)除了第1次請求伺服器,後面每一次請求伺服器,都要帶上cookie,浪費帶寬,請求速度會慢一點。
2)因為cookie是存在浏覽器端的,我們可以銷毀掉,可以篡改它
3)有的使用者,會在浏覽器端,禁用cookie
....
設定cookie的生存周期:
res.cookie("username","wc",{maxAge:60000*60*24*7,httpOnly:true})
除了第1次請求,後面每一次請求,都會帶上cookie,在伺服器端,就可以
擷取cookie,需要子產品:
npm i cookie-parser
使用:
let cookieParser = require("cookie-parser")
app.use(cookieParser())
req.cookies // 得到用戶端請求時,傳遞過一過來cookie
5.4 cookie記錄上一次通路的時間
app.get("/", (req, res) => {
// 擷取cookie 第1次擷取不到,值是und
let last = req.cookies.last;
// 第1次通路伺服器 需要種植一個cookie
//在浏覽器種植時間一年。
res.cookie("last", new Date().toLocaleString(), { maxAge: 60000 * 60 * 24 * 356 });
if (last) {
res.send(`你上一次通路的時間是:${last}`)
} else {
// 第1次通路
res.send(`這是你第1次通路本網站`)
}
})
5.5 session的使用
session的作用:在一次會話的多次請求之間共享資料,将資料儲存到伺服器端。
Session基于Cookie技術實作
session是伺服器端的會話技術
從浏覽器第一次向伺服器發起請求建立會話, 直到其中一方斷開為止會話結束。
session的特點:
- session存儲資料在伺服器
- session存儲任意類型的資料(Object)
- session存儲大小和數量沒有限制(在伺服器記憶體)
- session存儲相對安全
const session = require('express-session')
// 配置session
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
// session是基于cookie的
cookie: { maxAge:60000*10 }//id存在10分鐘
}))
app.get("/",(req,res)=>{
// session也是存數資料的,你可以把session了解成一片存儲資料的區域
// 你不需要種植cookie,内部會自動幫你種植
req.session.last = "2021-09-08"; // 當請求/時,給session區域儲存一個資料
// 後面的請求,班長會帶着編号來請求,會根據編号找到他對應的session
console.log("擷取班長的session中對應的資料:",req.session.last);
res.send("hello session")
})
cookie和session的選擇
-
cookie将資料儲存在浏覽器端,資料相對不安全.
建議敏感的或大量的資料不要放在cookie中,而且資料大小是有限制的
成本低,對伺服器要求不高
-
session将資料儲存在伺服器端記憶體,資料相對安全.
資料的大小要比cookie中資料靈活很多
成本較高,對伺服器壓力較大
6 Express中間件
路由是一個特殊的中間件,如果你要定義一個正經的中間件,必須要加next。next表示放行。
6.1 next介紹
express-next方法:
1.use既可以處理沒有路由位址的請求, 也可以處理有路由位址請求
2.use既可以處理get請求, 也可以處理post請求
3.在處理請求的時候是從上至下的判斷的, 哪一個先滿足就哪一個來處理
4.如果在處理請求的回調函數中沒有調用next方法, 那麼處理完之後就不會繼續往下判斷了
5.如果在處理請求的回調函數中調用了next方法,那麼處理完之後還會繼續往下判斷
6.2 next使用
// 中間件的書寫順序需要特别注意
// 如果沒有寫路徑,表示所有的請求都要經過此中間件
app.use((req,res,next)=>{
console.log("所有請求都要經過~");
// 放行
next()
})
// 不分是post還是get
// 普通的中間件
app.use("/abc",(req,res,next)=>{
console.log("我是一個中間件 111 ");
// 放行
next()
})
app.use("/abc",(req,res,next)=>{//一樣的名字會繼續執行 直到沒有next或者路徑不一樣
console.log("我是一個中間件 222");
// 放行 才能走到下面的路由 注釋掉不行
next()
})
/// 路由
app.get('/abc',(req, res, next)=>{
console.log('get1 /api');
next();
});
6.3 next正确使用方式
1)通過next方法, 我們可以将同一個請求的多個業務邏輯拆分到不同的方法中處理。
2)這樣可以提升代碼的可讀性和可維護性, 以及保證代碼的單一性。
6.4 express中間件
1.什麼是中間件?
- 中間件的本質就是一個函數, 這個函數接收3個參數request請求對象、response響應對象、next函數
- 當請求進來,會從第一個中間件開始進行比對。如果比對則進入,如果不比對,則向後依次對比比對
2.中間件的作用?
- 将一個請求的處理過程,分發到多個環節中,目的效率高,便于維護。即每個環節專門幹一件事
3.中間件的分類
3.1 應用級别中間件
綁定到app執行個體上的中間件
例如: app.get / app.post
3.2 路由級别中間件
綁定到router執行個體上的中間件
例如: router.get / router.post
3.3 錯誤進行中間件
與其他中間件函數的定義基本相同,
不同之處在于錯誤處理函數多了一個變量:err,即它有4個變量:err, req, res, next
3.4 内置中間件
express.static()、express.json()、express.urlencoded()、...
3.5 第三方中間件
cookie-parser、...
7 Express腳手架
7.1 通過express搭建項目
安裝腳手架:
npm install express-generator -g
通過腳手架去建立項目:
express myapp
進入myapp中:
cd myapp
跑環境:
npm i
運作項目:
npm start (是npm run start的簡寫)
預設建立出來的項目,它使用的模闆引擎是jade模闆引擎,不需要我們不學習。
後面建立項目時,生的項目使用的模闆引擎是ejs的,建立項目是指定模闆引擎,如下:
指令:express -e myapp2
7.2 生成的app.js
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
// http-errors 用來處理錯誤的
var createError = require('http-errors');
// 列印日志
var logger = require('morgan');
// 引入二級路由子產品(路由檔案)
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
// 建立app應用
var app = express();
// 告訴epxress,模闆放在了什麼地方
app.set('views', path.join(__dirname, 'views'));
// 告訴express,使用的模闆引擎是jade
app.set('view engine', 'jade');
// 使用中間件
app.use(logger('dev')); // 日志中間件
// 解析前端傳的json資料
app.use(express.json());
// 解析前端傳的表單資料
app.use(express.urlencoded({ extended: false }));
// 解析cookie
app.use(cookieParser());
// 托管靜态資源
app.use(express.static(path.join(__dirname, 'public')));
// 配置一級路由
app.use('/', indexRouter);
app.use('/users', usersRouter);
// 配置中間件
app.use(function(req, res, next) {
// 放行
next(createError(404));
});
// 配置中間件 err
// 叫錯誤進行中間件
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;