[TOC]html
Express 是一個基於 Node.js 封裝的上層服務框架,它提供了更簡潔的 API 更實用的新功能。它經過中間件和路由讓程序的組織管理變的更加容易;它提供了豐富的 HTTP 工具;它讓動態視圖的渲染變的更加容易;它還定義了一組可拓展標準。前端
npm install express -S
複製代碼
let express = require('express')
let app = express()
app.get('/',(req,res) => res.end('hello world'))
app.listen(3000,() => console.log('Server is running...'))
複製代碼
運行示例node
在web網站後端開發的過程當中,咱們每每須要把一些靜態文件夾暴露出去,用戶能夠根據url地址去訪問到其中的內容,這些靜態文件每每也稱之爲公共資源,利用express框架能夠方便地託管靜態文件。git
public
靜態資源的文件夾方法一(推薦)github
app.use('/public/',express.static('./public'))
複製代碼
爲 app.use()
方法傳遞兩個參數,第一個參數爲訪問的URL前綴,第二個爲要託管的目錄即要暴露的文件目錄web
let express = require('express');
let app = express()
//設置靜態資源
// 方法一
app.use('/public/',express.static('./public'))
app.listen(3000,() => console.log('Server is running...'))
複製代碼
示例shell
方法二數據庫
app.use(express.static('./public'))
複製代碼
方法二在方法一的基礎上,省略第一個參數,直接指定暴露的靜態資源文件夾express
let express = require('express');
let app = express()
//設置靜態資源
// 方法二
app.use(express.static('./public'))
app.listen(3000,() => console.log('Server is running...'))
複製代碼
示例npm
方法三
app.use('/static/',express.static('./public'))
複製代碼
同方法一傳參相似,只不過將第一個參數設置爲你想訪問的URL前綴,即指定前綴的別名
let express = require('express');
let app = express()
//設置靜態資源
// 方法三
app.use('/static/',express.static('./public'))
app.listen(3000,() => console.log('Server is running...'))
複製代碼
示例
在post請求中,請求的參數包含在 請求的body中,咱們要獲取post請求的數據,便是要獲取request.body裏面的數據
可是,在默認狀況下,咱們使用 req.body獲取到的內容爲undefine,這裏須要使用一箇中間件
body-parser
來解析傳入的請求主體,使req.body能夠被訪問
1. 安裝 body-parser
npm install body-parser express -S
複製代碼
2. 建立server.js
// server.js
//引入模塊
const express = require('express')
const bodyParse = require('body-parser')
// 建立服務器對象
const app = express()
/** * 經過 body-parser中間件解析req.body * 根據不一樣的 Content-Type分別有以下兩種不一樣的配置 * post請求體中的Content—Type爲:application/x-www-form-urlencoded,使用配置1 * post請求體中的Content-Type爲:application/json,使用配置2 */
app.use(bodyParse.urlencoded({extended:false}))
app.use(bodyParse.json())
//配置訪問路由,返回post請求中的name參數
app.post('/post',(req,res)=>{
const result = req.body
console.log(result)
res.end(result.name)
})
app.listen(3000,()=>console.log('Server is running on localhost:3000'))
複製代碼
3. 開啓服務器,可經過postman訪問URL,自行配置body裏面的參數信息,以及指定Content-Type
4. 最後點擊左下角的body,便可查看咱們服務器中的返回信息
前面咱們學習瞭如何在Nodejs中使用
art-template
,在express一樣可使用,接下來咱們就來看看,如何在express中使用art-template
1. 在express中使用art-template,首先要安裝以下兩個模塊
npm install art-template express-art-template -S
複製代碼
2. 添加模版界面
// index.html
<!DOCTYPE html>
<html lang="en">
<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 }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>My name is {{ name }}</p>
<p>I come from {{ from }}</p>
<p>I like {{each hobbies}} {{ $value }} {{ /each }}</p>
</body>
</html>
複製代碼
3. 添加server.js文件
const express = require('express')
const app = express()
// 配置 express-art-template模版引擎,
//配置以後,服務器請求事件的回調函數的響應對象上會增長一個 render方法,用於渲染模版字符串返回渲染以後的結果
// 第一個參數 html 爲模版文件拓展名,表示模版文件必須是HTML文件
app.engine('html',require('express-art-template'))
app.get('/',(req,res)=>{
res.render('./index.html',{
title: '我的介紹',
name: 'Kobe',
form: 'America',
bobbies: ['basketball','swimming']
})
})
app.listen(8000,()=>console.log('Server is running on localhost:3000'))
複製代碼
4. 啓動服務器,調用URL,咱們發現,報以下錯誤
Error: Failed to lookup view "./index.html" in views directory "C:\Users\admin\Desktop\work\ForStudy\8.Node.js\DemoFolder\express-art-template-demo\views"
複製代碼
錯誤分析
app.set('views', '替換的文件路徑') // 第一個參數必須爲:views
複製代碼
路由分爲前端路由和後端路由,這裏咱們主要談論的過後端路由,即URL地址
後端路由
對於普通網站,全部的連接都是URL地址,URL地址即對應服務器上面的資源
前端路由
前端路由主要經過hash(#)來實現,經過hash值的改變來切換界面,同同時,hash值的改變並不會帶來http請求的從新響應,使得加載頁面的性能更好
經過前面的學習咱們知道,能夠經過express的get和post方法,對不一樣的URL地址作出響應,最終將結果返回給客戶端
**問題描述:**一旦咱們的項目界面多了起來,須要處理的請求路徑就會比較多,若是所有寫在一個文件,就會使得文件難以維護,因而咱們能夠提取路由文件,專門用來配置路由,最後把路由對象導出掛載到服務器上便可
實現:
使用 npm init -y 初始化,而且安裝 express 模塊
npm init -y
npm install express -S
複製代碼
建立server.js文件
// server.js
const express = require('express')
const server = express()
server.listen(3000,()=>{
console.log('Server is running on localhost:3000')
})
複製代碼
路由文件
// router.js
// 引入express而且獲取路由對象
const app = require('express')
const router = app.Router()
// 配置路由對象
router.get('/',(req,res)=>{
res.send('主頁')
})
router.get('/login',(req,res)=>{
res.send('登錄')
})
router.get('/register',(req,res)=>{
res.send('註冊')
})
// 導出路由對象
module.exports = router
複製代碼
在server.js文件中掛載路由對象
// server.js
const express = require('express')
const server = express()
//掛載路由對象
const router = require('./router')
server.use(router)
server.listen(3000,()=>{
console.log('Server is running on localhost:3000')
})
複製代碼
演示
在這裏,咱們一塊兒經過express框架,來實現一個擁有增刪改查功能的簡易版學生管理系統
一共有以下幾個文件
// db.json
{
"students": [
{
"id": 1,
"name": "YaoMing",
"sex": "M",
"hobbies": [
"Basketball",
"ComputerGame",
"eating"
]
},
{
"id": 2,
"name": "YiJianLian",
"sex": "M",
"hobbies": [
"Basketball",
"earnMoney",
"coding"
]
},
{
"id": 3,
"name": "Kobe",
"sex": "M",
"hobbies": [
"basketball",
"swimming",
"sleep"
]
}
]
}
複製代碼
// StudentApi.js
/** * 提供一個簡單的CRUD接口 * 可經過以下增刪改查的接口,實現一個簡易的學生管理系統 * 同時,可做爲nodejs增刪改查的模板 */
const fs = require('fs')
// 提取數據源地址,方便後續維護
const dataBase = './db.json'
/** * 新增學生信息 * Param:要新增的學生對象 * 調用:add(student) * */
exports.add = (student)=>{
fs.readFile(dataBase,(err,data)=>{
// 錯誤處理
if(err){
return console.log('readFiel db.json error...')
}
// 獲取學生數組
var students = JSON.parse(data).students
// 爲新增的學生對象設置id值
if(students.length === 0){
student.id = 1
}
student.id = students[students.length-1].id + 1
// 將新增的學生對象添加到學生數組
students.push(student)
let dataStr = JSON.stringify({studnets:studnets})
// 將新增完成的學生數組寫入文件
fs.writeFile(dataBase,dataStr,(err)=>{
if(err){
return console.log('write to db.json failed...')
}
return console.log('添加成功')
})
})
}
/** * 更新學生信息 * Param: 要修改的學生對象 */
exports.update = (student)=>{
fs.readFile(dataBase,(err,data)=>{
// 錯誤處理
if(err){
return console.log('readFiel db.json error...')
}
// 獲取學生數組
var students = JSON.parse(data).students
// 更新標識,用來判斷是否有數據被更新
var isUpdate = false
// 遍歷學生數組,找到要更新的那一個學生信息
for(var i = 0;i<students.length;i++){
// 當學生信息都沒有發生變化的時候,不作更新
if(students[i].id === student.id){
if(students[i].name == student.name && students[i].sex == student.sex && students[i].hobbies.toString() == student.hobbies.toString()){
console.log('未作任何更新,沒法提交學生信息')
}else{
students[i].name = student.name
students[i].sex = student.sex
students[i].hobbies = student.hobbies
isUpdate = true
}
}
}
// 根據 isUpdata標識,判斷是否有數據更新
if(isUpdate){
let dataStr = JSON.stringify({students:students})
fs.writeFile(dataBase,dataStr,(err)=>{
if(err){
return console.log('write to db.json failed...')
}
return console.log('跟新成功!')
})
}else{
console.log('跟新失敗')
}
})
}
/** * 查找全部學生信息,經過callback回調函數將students數組返回 */
exports.searchAll = (callback)=>{
fs.readFile(dataBase,(err,data)=>{
if(err){
return console.log('read file db.json err...')
}
callback(JSON.parse(data).students)
})
}
/** * 經過id刪除學生信息 * Param: id:要刪除的學生id */
exports.delete = (id)=>{
fs.readFile(dataBase,(err,data)=>{
if(err){
return console.log('readFiel db.json error...')
}
var students = JSON.parse(data).students
var isDelete = false
// 遍歷學生數組,刪除指定id的學生信息
for(var i = 0;i<students.length;i++){
if(students[i].id === id){
students.splice(i,1)
isDelete = true
}
}
// 經過 isDelete標識判斷是否刪除成功
if(isDelete){
let dataStr = JSON.stringify({students:students})
fs.writeFile(dataBase,dataStr,(err)=>{
if(err){
return console.log('write to db.json failed...')
}
return console.log('刪除成功!')
})
}else{
console.log('沒有找到要刪除的數據')
}
})
}
複製代碼
// test.js
const api = require('./StudentApi')
var student = {
"id": 3,
"name": "Kobe",
"sex": "M",
"hobbies": [
"basketball",
"swimming",
"sleep"
]
}
// api.add(student,null)
// api.searchAll((data)=>{
// console.log(data)
// })
// api.delete(4)
// api.update(student)
複製代碼
**middleware:**即中間件,在express中是很重要的一個概念
**官網的介紹:**Express 是一個路由和中間件 Web 框架,其自身只具備最低程度的功能:Express 應用程序基本上是一系列中間件函數調用。
**做用:**簡單來講,就是當咱們在瀏覽器中發送URL請求開始,到咱們在瀏覽器接收到數據和看到界面渲染爲止,這中間的全部過程都是經過 express中間件來完成的
其實在咱們以前的學習過程當中,咱們已經使用過express中間件了,如今咱們來一塊兒回顧一下
這兩種場景都用到了express中間件,咱們發現,他們都有一個共同的特徵,即都是經過 app.use方法來調用的
const express = reuire('express')
const app = express()
// 開放靜態資源
app.use('/public/',express.static('./public'))
// 獲取post請求參數配置
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
複製代碼
分類:
express應用程序能夠執行以下幾種類型的中間件
基礎:(重要)
中間件簡單來講就是一系列函數,就是在請求返回以前,咱們對數據進行的一系列處理邏輯的執行函數
每個函數都包含三個參數:req,res,next
req:包含請求對象相關信息
res:包含相應對象相關信息
next():控制中間件傳播流程
// 這裏拿一箇中間件作示範
// 以下,use方法裏面的多個函數即爲中間件的堆棧,能夠經過next方法,讓他們按照順序執行,若是前面的方法沒有調用next()方法,則後面的函數就不會執行,請求將會停留在該中間件中,不會繼續執行
app.use('./demo',function(req,res,next){
console.log('第一個中間件函數')
next()
},function(req,res,next){
console.log('第二個中間件函數')
// next()
},function(req,res,next){
console.log('第三個中間件函數,若是上面的方法沒有調用next(),則這裏不會執行')
next()
})
// demo路徑的第二個路由,可否執行要依賴於前面的中間件是否調用了next()方法
app.use('./demo',function(req,res,next){
console.log('第二個路由的中間件1')
next()
},function(req,res,next){
console.log('第二個路由的中間件2')
// next()
},function(req,res,next){
res.send('hello world')
})
複製代碼
使用
app.use()
或者app.METHOD()
函數將 中間件綁定到應用程序對象的實例,其中METHOD是中間函數處理的請求的小寫HTTP方法
**Demo1:**未指定路徑的中間件,全部的請求都會先執行該方法
const app = express()
app.use(function(req,res,next){
console.log(Date.now())
next()
})
複製代碼
**Demo2:**指定路徑上的中間件,只有符合指定路徑的請求才會調用該中間件
const app = express()
// 只有指定路徑下的請求才會調用該中間件
app.use('/a',function(req,res,next){
console.log(Date.now())
next()
})
複製代碼
**Demo3:**能夠經過添加多個function,實現中間件堆棧的調用效果
const app = express()
app.use('/user', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
app.get('/user',(req,res)=>{
console.log('user目錄')
res.send('user目錄')
})
複製代碼
結果:
Request URL: /user
Request Type: GET
user目錄
複製代碼
**Demo4:**爲同一個路徑定義多個路由,若是前面路由使請求結束,則後面路由不會調用,不然會按順序調用
// Demo4:爲同一個路徑定義多個路由,若是前面路由使請求結束,則後面路由不會調用,不然會按順序調用
app.get('/more',(req,res,next)=>{
console.log('more第一個路由的第一次調用')
next()
},function(req,res,next){
// console.log('隨便打印點什麼')
// next()
res.send('這裏使請求結束,後續的路由將不會調用')
})
app.get('/more',(req,res,next)=>{
console.log('more第二個路由的第一次調用')
next()
},function(req,res,next){
res.send('more第二個路由的第二次調用')
})
複製代碼
Demo5:
// Demo5:經過 next('route')方法跳出堆棧,將控制權交給下一個路由
app.get('/demo5',(req,res,next)=>{
console.log('demo5第一個路由的第一次調用')
next()
},function(req,res,next){
console.log('welcome to demo5')
//next()
next('route')
},function(req,res,next){
console.log("若是前面調用了next('route')方法,這裏將不會調用")
next()
})
app.get('/demo5',(req,res,next)=>{
console.log('demo5第二個路由的第一次調用')
next()
},function(req,res,next){
res.send('demo5第二個路由的第二次調用')
})
複製代碼
結果:
demo5第一個路由的第一次調用
welcome to demo5
demo5第二個路由的第一次調用
//瀏覽器展現
demo5第二個路由的第二次調用
複製代碼
路由中間件相似於應用層中間件,只不過在應用層中間件的基礎上,將路由模塊抽離出來,實現方法同上
這裏只作簡單Demo示例
Demo
const express = require('require')
const app = express()
const router = app.Router()
router.use('/user', function(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}, function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
router.use('/user', function(req, res, next) {
console.log(Date.now());
next();
}, function (req, res, next) {
res.end('hello world')
});
複製代碼
錯誤處理中間件用法同上,只有一點不一樣
錯誤處理中間件始終採用四個自變量。必須提供四個自變量,以將函數標識爲錯誤處理中間件函數。即便無需使用
next
對象,也必須指定該對象以保持特徵符的有效性。不然,next
對象將被解釋爲常規中間件,從而沒法處理錯誤。
Demo:
app.use(function(err, req, res, next) {
console.error(err.stack);
res.status(500).send('Something broke!');
});
複製代碼
Express 中惟一內置的中間件函數是
express.static
**語法:**express.static(root, [options])
參數:
root
自變量指定從其中提供靜態資源的根目錄。- options包含一系列的參數配置
**做用:**配置應用程序的靜態文件目錄,可經過靜態路徑直接在瀏覽器獲取靜態文件目中的文件
**Demo:**對於應用程序,能夠配置多個靜態目錄
app.use(express.static('public'));
app.use(express.static('uploads'));
app.use(express.static('files'));
複製代碼
使用:
- 第三方中間件屬於nodejs模塊,須要先安裝
- 經過在應用層或路由器層的應用程序中將其加裝入
**Demo:**第三方中間件 cookie-parser的使用
npm i cookie-parser -S
複製代碼
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
// load the cookie-parsing middleware
app.use(cookieParser());
複製代碼