【重點突破】——使用Express創建一個web服務器
一、引言
在自學node.js的過程中有一個非常重要的框架,那就是Express。它是一個基於NodeJs http模塊而編寫的高層模塊,彌補http模塊的繁瑣和不方便,能夠快速開發http服務器。這裏,就要用Express創建一個Web服務器,用來深入的理解這個框架,並熟悉創建Web服務器的過程。
二、核心概念——中間件
Express 是一個自身功能極簡,完全是由路由和中間件構成一個的 web 開發框架:從本質上來說,一個 Express 應用就是在調用各種中間件。
中間件(Middleware) 是一個函數,它可以訪問請求對象(request object (req)), 響應對象(response object (res)), 和 web 應用中處於請求-響應循環流程中的中間件,一般被命名為 next 的變量。
中間件的功能包括:
- 執行任何代碼。
- 修改請求和響應對象。
終結請求-響應循環。調用堆棧中的下一個中間件。
如果當前中間件沒有終結請求-響應循環,則必須調用 next() 方法將控制權交給下一個中間件,否則請求就會掛起。
Express 應用可使用如下幾種中間件:
- 應用級中間件
- 路由級中間件
- 錯誤處理中間件
- 內置中間件
- 第三方中間件
使用可選則掛載路徑,可在應用級別或路由級別裝載中間件。另外,你還可以同時裝在一系列中間件函數,從而在一個掛載點上創建一個子中間件棧。
app.use(url, (req, res, next)=>{
//.....中間件要執行的代碼
next( ); //調用下一個中間件或路由
三、模塊下載
因為創建Web服務器要用到第三方模塊的mysql和Express,所以需要在創建新項目之後,在NPM中進行下載,安裝這兩個模塊,具體過程如下:
- Webstorm創建新項目project,右鍵點擊project
- show in Explorer 進入目標文件夾
- 按shift 同時點擊右鍵,在空白面板處
- 在此處打開命令窗口
- >npm i mysql 等待下載
- >npm i express 等待下載
下載完成後,webstorm中新創建的project下會自動更新出一個node_modules目錄,裏面會有需要的mysql和Express。
四、引例說明
使用Express創建一個web服務器,可以向客戶端提供一個 /index響應,內容是一個HTML頁面,其中還使用一個index.css文件/index.js文件
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="index.css"/>
</head>
<body>
<h1>INDEX.HTML</h1>
<script src="index.js"></script>
</body>
</html>
css文件和js文件此處省略
//app.js執行文件
const http = require(‘http‘);
const express = require(‘express‘);
var app = express();
http.createServer(app).listen(8080);
app.get(‘/index‘,(req,res)=>{
res.sendFile(__dirname+‘/pulic/index.html‘);
});
app.get(‘/index‘,(req,res)=>{
res.sendFile(__dirname+‘/pulic/index.css‘);
});
app.get(‘/index‘,(req,res)=>{
res.sendFile(__dirname+‘/pulic/index.js‘);
});
小坑:如果index.html室友路由引入的,即使裏面的index.css和index.js引入到了html中,若沒有通過路由引入到app.js文件中,則這兩個css與js文件是存在,但不響應的。所以,必須都通過路由引入到app.js文件中。但是,這同樣會有一個問題,那就是如果要引入的文件太多,又必須要一個不漏的引入,那這樣一個一個引太繁瑣了,工作量太大,這就是中間件的重要性了,使用中間件可以方便快鍵的引入所需的所有文件。
Express 4.x官方還提供了一個中間件函數:app.use(express.static(‘public‘));//若客戶端請求了/public目錄下的某個資源,它可以直接向客戶端返回,不會再調用後續的路由。
五、web服務器創建
要求:使用Express創建Web服務器應用,可以接收如下的請求:
1、編寫SQL:創建數據庫dangdang,書籍信息表book(bid,title,price,pubDate-出版日期,into-內容簡介),並插入4行書籍記錄。
2、至少可以向客戶端提供如下靜態資源:
/public/booklist.html 初始時顯示一個空白的表格,頁面加載完成後向服務器異步請求所有的書籍信息。
/public/jquery-1.11.3.js 在DIV中顯示某一本書的詳情
/public/book_detail.html 在DIV中顯示某一本書的詳情
/public/book_add.html 顯示一個添加書籍的表單,點擊“提交”按鈕,異步提交給服務器
/public/book_update.html 顯示一個修改書籍的表單,輸入域中是當前要修改的書籍信息,點擊“提交”按鈕,異步提交給服務器。
3、以及如下動態資源地址——註意:下述地址都使用Ajax異步請求
GET /book 向客戶端輸出書籍表中的所有記錄,以JSON格式
GET /book/:id 向客戶端輸出指定編號的書籍全部信息,以JSON格式
DELETE /book/:id 刪除指定編號的書籍記錄,向客戶端輸出{code:1,bid:xx}或者{code:2,msg:‘指定書籍編號不存在‘}
POST /book 接收客戶端提交的請求主體數據(title/price/pubDate/intro),執行書籍添加操作保存入數據庫,向客戶端輸出{code:1,bid:xx}
PUT /book 接收客戶端提交的請求主體數據(bid/title/price/pubDate/intro),執行書籍更新操作修改數據庫中對應的書籍,向客戶端輸出{code:1,affectRows:1}
實現:
DROP DATABASE IF EXISTS dangdang;
CREATE DATABASE dangdang CHARSET=UTF8;
USE dangdang;
CREATE TABLE book(
bid INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(64),
price DECIMAL(8,2),
pubDate BIGINT,
intro VARCHAR(2048)
);
INSERT INTO book VALUES
(NULL, ‘西遊記‘, ‘35.5‘, ‘1350123456789‘,‘描述了一個和尚和三個妖怪的故事‘),
(NULL, ‘水滸傳‘, ‘45.5‘, ‘1360123456789‘,‘描述了105個男人和3個女人的故事‘),
(NULL, ‘紅樓夢‘, ‘55.5‘, ‘1370123456789‘,‘描述了1個富二代的故事‘),
(NULL, ‘三國誌‘, ‘65.5‘, ‘1380123456789‘,‘描述了群雄爭霸的故事‘);
//book_list.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>書籍列表</h1>
<hr/>
<table border="1" width="100%">
<thead>
<tr>
<th>編號</th>
<th>書名</th>
<th>價格</th>
<th>出版日期</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<td colspan="5">信息加載中....</td>
</tbody>
</table>
<script src="js/jquery-1.11.3.js"></script>
<script>
//待當前頁面加載完成,異步請求所有書籍信息 GET /book
$.ajax({
type:‘GET‘,
url:‘/book‘,
success:function(list){
//遍歷list數組,每個obj拼接為一個TR>TD*5,TBODY
var html =‘‘;
for(var book of list){
html +=`
<tr>
<td>${book.bid}</td>
<td>${book.title}</td>
<td>${book.price}</td>
<td>${book.pubDate}</td>
<td>
<a class="detail" href="#">詳情</a>
<a class="delete" href="#">刪除</a>
<a class="update" href="#">修改</a>
</td>
</tr>
`;
}
$(‘tbody‘).html(html);
}
});
</script>
</body>
</html>
//book_detail.html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
border-bottom: 1px solid #aaa;
padding: 1em;
}
</style>
</head>
<body>
<h1>書籍詳情</h1>
<hr/>
<div id="bid">
<b>書籍編號:</b>
<p>xxx</p>
</div>
<div id="title">
<b>書籍標題:</b>
<p>xxx</p>
</div>
<div id="price">
<b>單價:</b>
<p>xxx</p>
</div>
<div id="pubDate">
<b>出版日期:</b>
<p>xxx</p>
</div>
<div id="intro">
<b>內容簡介:</b>
<p>xxx</p>
</div>
<script src="js/jquery-1.11.3.js"></script>
<script>
//待頁面加載完成,異步請求指定編號的書籍詳情
//console.log(location);
//console.log(location.search);
//console.log(location.search.split(‘=‘));
var bid = location.search.split(‘=‘)[1];
$.ajax({
type: ‘GET‘,
url: ‘/book/‘+bid,
success: function(book){
console.log(‘成功接收到服務器返回的書籍信息‘);
console.log(book);
$(‘#bid p‘).html(book.bid);
$(‘#title p‘).html(book.title);
$(‘#price p‘).html(‘¥‘+book.price);
var d = new Date(book.pubDate);
$(‘#pubDate p‘).html(d);
$(‘#intro p‘).html(book.intro);
}
});
</script>
</body>
</html>
//其余兩個html內容省略
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>更新書籍內容</h1>
<hr/>
<script src="js/jquery-1.11.3.js"></script>
</body>
</html>
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>添加書籍</h1>
<hr/>
<script src="js/jquery-1.11.3.js"></script>
</body>
</html>
//執行程序app.js
const http = require(‘http‘);
const express = require(‘express‘);
const book = require(‘./book‘);
var app = express();
http.createServer(app).listen(8080);
//使用中間件向客戶端返回靜態內容
app.use(express.static(‘public‘));
//定義路由,向客戶端返回動態內容
app.get(‘/book‘, book.getAll);//自建一個book模塊,調用getAll方法
//自建模塊book.js
const mysql = require(‘mysql‘);
//數據庫連接池
var pool = mysql.createPool({
user:‘root‘,
database:‘dangdang‘,
connectionLimit:5
});
module.exports = {
getAll:(req, res)=>{
pool.getConnection((err,conn)=>{
conn.query(‘SELECT * FROM book‘,(err,result)=>{
//把查詢結果集轉換為JSON字符串,輸出給客戶端
res.json(result);
conn.release();//釋放連接回連接池
})
})
}
};
效果:
【重點突破】——使用Express創建一個web服務器