基礎的 express 實現(xiàn)靜態(tài)文件訪問
index.js 開啟 http 服務
const express = require('express'); // 引入 express 模塊
const globalConfig = require('./config'); // 導入全局配置
const app = new express(); // 實例化一個 express
app.use(express.static(globalConfig['page_path'])); // 告訴 express 示例, 靜態(tài)文件的位置
app.listen(globalConfig['port']); // 監(jiān)聽配置文件中的端口
server.conf是服務的配置文件
port=8081
page_path=page
config.js 用來處理 server.conf ,將配置文件轉換為配置對象
/*
將配置文件格式化成對象鍵值對的形式
*/
const fs = require('fs'); // 引入 fs 模塊
let globalConfig = {}; // 定義全局配置對象
let conf = fs.readFileSync('./server.conf'); // 同步讀取 server.conf 文件
let confArr = conf.toString().split("\n"); // 通過回車符拆分
for (let i = 0, len = confArr.length; i < len; i++) {
globalConfig[confArr[i].split('=')[0]] = confArr[i].split('=')[1]
}
module.exports = globalConfig; // 將配置對象導出
page 文件夾中存放頁面文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
然后運行 index.js,瀏覽器訪問127.0.0.1:8081

基于 express 搭建 web 服務
這個不同于上面簡單的web服務,這是一個完整的簡易 web 服務。
首先目錄是這樣的:

server.conf
盡管它不在一個文件夾中, 也是很重要的一環(huán)
這個文件定義了整個服務的基本信息。
port=8081
page_path=page
web_path=web
盡管只有簡單的三行, 但是業(yè)務邏輯復雜之后, 這個文件也會逐漸豐滿的。如果不定義此文件,在需要這些字段的時候,就會變得很麻煩。例如改端口號, 可能很多地方都需要改, 但是有這個文件, 只需要修改文件中的端口就好了。
config.js
有了配置文件, 肯定需要一段代碼去解析配置文件。
/*
將配置文件格式化成對象鍵值對的形式
*/
const fs = require('fs'); // 引入 fs 模塊
let globalConfig = {}; // 定義全局配置對象
let conf = fs.readFileSync('./server.conf'); // 同步讀取 server.conf 文件
let confArr = conf.toString().split("\n"); // 通過回車符拆分
for (let i = 0, len = confArr.length; i < len; i++) {
globalConfig[confArr[i].split('=')[0]] = confArr[i].split('=')[1]
}
module.exports = globalConfig; // 將配置對象導出
這個文件的目的是將上面的配置文件格式化為對象的形式:
{
port: '8081',
page_path: 'page',
web_path: 'web',
'': undefined
}
然后在需要配置項的地方使用globalConfig.xxx的形式即可。
index.js
此文件用于創(chuàng)建服務。
const express = require('express'); // 引入 express 模塊
const globalConfig = require('./config'); // 導入全局配置
const app = new express(); // 實例化一個 express
const loader = require('./loader')
app.use(express.static(globalConfig['page_path'])); // 告訴 express , 靜態(tài)文件的位置
app.post("/dosomething", loader.get("/dosomething")) // 請求數(shù)據(jù)的方法
app.listen(globalConfig['port']); // 監(jiān)聽配置文件中的端口
app.post("/dosomething", loader.get("/dosomething")):
假設點擊了一個按鈕, 這個按鈕要獲取數(shù)據(jù)。這個請求可能是www.example.com/dosomething?name=xx&age=yy, 然后服務監(jiān)聽到這個請求, 然后就會去loader.js中尋找對應的處理函數(shù), 對這個請求進行處理。至于參數(shù)在哪里, 這個請求是怎么處理的, 在下面會介紹。
這個時候服務已經(jīng)搭好, 已經(jīng)可以訪問靜態(tài)文件了。
page
page 文件夾之下都是靜態(tài)資源信息。如果請求為靜態(tài)資源, 會直接去express.static參數(shù)的文件夾下尋找。
web
如果說 page 文件夾存放靜態(tài)資源, 那么 web 的作用就是存儲獲取動態(tài)數(shù)據(jù)的方法。
在這里, 有許多的 controller,是用來處理邏輯的。這里有一個dosomething的例子:
const timeUtil = require('../Utils/timeUtil')
const writeRes = require('../Utils/resultUtil')
let path = new Map()
let dosomething = require('../dao/somethingDao');
function something(request, response) {
request.on('data', function (data) {
dosomething.dosomething(data, timeUtil.getNow(), function (res) {
response.writeHead(200)
response.write(writeRes.writeResult("success OK", timeUtil.getNow(), res))
response.end()
})
})
}
path.set("/dosomething", something)
module.exports = path
請求的url在request里面。可以使用url模塊解析這個url獲取對應的參數(shù)信息。data就是post請求發(fā)送過來的參數(shù)。這里忽略了對 data 的解析。
loader.js
const fs = require('fs')
const globalConfig = require('./config')
let controllerSet = []
let pathMap = new Map()
let files = fs.readdirSync(globalConfig['web_path']) // 讀取文件夾
for (let i = 0, len = files.length; i < len; i++){ // 讀取 files 中所有的文件
let temp = require('./' + globalConfig['web_path'] + '/' + files[i]) // 引入 web 里面的文件
if(temp.path){
for (let [key, value] of temp.path){ // 讀取 每一個文件的 path
if(pathMap.get(key) == null){ // 如果在 pathMap 中沒有, 就添加進去
pathMap.set(key, value)
}else { // 如果進入 else , 說明 url 重了。 這當然不允許
throw new Error("url error, url: " + key);
}
controllerSet.push(temp)
}
}
}
module.exports = pathMap // 將 pathMap 導出
讀取上面的web文件夾, 引入所有的js文件, 引入一個解析一個, 獲取到所有的處理動態(tài)數(shù)據(jù)的方法, 將這些方法全部放入一個叫做pathMap的Map中 ,然后將之導出, 在index.js里面引入pathMap。然后根據(jù)不同請求, get到loader里面對應的方法。
dao(Data Access Object)
此文件夾下有兩類文件,第一類只有一個, 叫做DBUtil.js,它用于創(chuàng)建一個與數(shù)據(jù)庫的鏈接。
let mysql = require('mysql')
function createConnection() {
return mysql.createConnection({
host: "127.0.0.1",
port: "3306",
user: "root",
password: "123546",
database: "test"
})
}
module.exports.createConnection = createConnection
第二類可能有很多個, 它們用于響應用戶請求對數(shù)據(jù)庫的增刪改查操作。
這里是上面dosomething的例子:
const DBUtil = require('./DBUtil') // 引入創(chuàng)建數(shù)據(jù)庫的工具方法
function dosomething(content, ctime, success) {
let sql = "insert into table (`content`, `ctime`) values (?, ?)" // 編寫數(shù)據(jù)庫查詢語句
let params = [content, ctime] // 定義參數(shù)列表
let connection = DBUtil.createConnection() // 創(chuàng)建一個數(shù)據(jù)庫的鏈接
connection.connect() // 連接
connection.query(sql, params, function (err, result) { // 進行查詢
if (!err){ // 如果過程沒有出錯
success(result)
} else {
console.log(err)
}
})
connection.end() // 查詢完畢一定要關閉數(shù)據(jù)庫的連接
}
module.exports.dosomething = dosomething // 將此方法導出,供 web 層使用
至此, 文件夾說明完畢。
回顧整個流程。
使用 express 開啟一個服務。
使用 app.get, app.post 等待對應的請求進來。
請求進來之后, 使用loader.get()拿到對應的處理方法。這個方法去查詢數(shù)據(jù)庫, 邏輯復雜的還要經(jīng)過邏輯處理流程, 查詢完畢之后執(zhí)行loader預先設置到的回調函數(shù), 這個回調函數(shù)返回給客戶端需要的數(shù)據(jù)。