基礎(chǔ)的 express 實(shí)現(xiàn)靜態(tài)文件訪問
index.js
開啟 http
服務(wù)
const express = require('express'); // 引入 express 模塊
const globalConfig = require('./config'); // 導(dǎo)入全局配置
const app = new express(); // 實(shí)例化一個(gè) express
app.use(express.static(globalConfig['page_path'])); // 告訴 express 示例, 靜態(tài)文件的位置
app.listen(globalConfig['port']); // 監(jiān)聽配置文件中的端口
server.conf
是服務(wù)的配置文件
port=8081
page_path=page
config.js
用來處理 server.conf
物赶,將配置文件轉(zhuǎn)換為配置對象
/*
將配置文件格式化成對象鍵值對的形式
*/
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; // 將配置對象導(dǎo)出
page 文件夾中存放頁面文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello, world!</h1>
</body>
</html>
然后運(yùn)行 index.js
白指,瀏覽器訪問127.0.0.1:8081
基于 express 搭建 web 服務(wù)
這個(gè)不同于上面簡單的web服務(wù),這是一個(gè)完整的簡易 web 服務(wù)酵紫。
首先目錄是這樣的:
server.conf
盡管它不在一個(gè)文件夾中告嘲, 也是很重要的一環(huán)
這個(gè)文件定義了整個(gè)服務(wù)的基本信息。
port=8081
page_path=page
web_path=web
盡管只有簡單的三行奖地, 但是業(yè)務(wù)邏輯復(fù)雜之后橄唬, 這個(gè)文件也會逐漸豐滿的。如果不定義此文件参歹,在需要這些字段的時(shí)候仰楚,就會變得很麻煩。例如改端口號犬庇, 可能很多地方都需要改僧界, 但是有這個(gè)文件, 只需要修改文件中的端口就好了臭挽。
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; // 將配置對象導(dǎo)出
這個(gè)文件的目的是將上面的配置文件格式化為對象的形式:
{
port: '8081',
page_path: 'page',
web_path: 'web',
'': undefined
}
然后在需要配置項(xiàng)的地方使用globalConfig.xxx
的形式即可欢峰。
index.js
此文件用于創(chuàng)建服務(wù)葬荷。
const express = require('express'); // 引入 express 模塊
const globalConfig = require('./config'); // 導(dǎo)入全局配置
const app = new express(); // 實(shí)例化一個(gè) 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è)點(diǎn)擊了一個(gè)按鈕纽帖, 這個(gè)按鈕要獲取數(shù)據(jù)宠漩。這個(gè)請求可能是www.example.com/dosomething?name=xx&age=yy
, 然后服務(wù)監(jiān)聽到這個(gè)請求, 然后就會去loader.js
中尋找對應(yīng)的處理函數(shù)抛计, 對這個(gè)請求進(jìn)行處理哄孤。至于參數(shù)在哪里照筑, 這個(gè)請求是怎么處理的吹截, 在下面會介紹。
這個(gè)時(shí)候服務(wù)已經(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
趁窃,是用來處理邏輯的。這里有一個(gè)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
模塊解析這個(gè)url
獲取對應(yīng)的參數(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){ // 讀取 每一個(gè)文件的 path
if(pathMap.get(key) == null){ // 如果在 pathMap 中沒有, 就添加進(jìn)去
pathMap.set(key, value)
}else { // 如果進(jìn)入 else 世吨, 說明 url 重了澡刹。 這當(dāng)然不允許
throw new Error("url error, url: " + key);
}
controllerSet.push(temp)
}
}
}
module.exports = pathMap // 將 pathMap 導(dǎo)出
讀取上面的web
文件夾, 引入所有的js
文件耘婚, 引入一個(gè)解析一個(gè)罢浇, 獲取到所有的處理動態(tài)數(shù)據(jù)的方法, 將這些方法全部放入一個(gè)叫做pathMap
的Map
中 边篮,然后將之導(dǎo)出己莺, 在index.js
里面引入pathMap
。然后根據(jù)不同請求戈轿, get
到loader
里面對應(yīng)的方法凌受。
dao(Data Access Object)
此文件夾下有兩類文件,第一類只有一個(gè)思杯, 叫做DBUtil.js
胜蛉,它用于創(chuàng)建一個(gè)與數(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
第二類可能有很多個(gè)色乾, 它們用于響應(yīng)用戶請求對數(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)建一個(gè)數(shù)據(jù)庫的鏈接
connection.connect() // 連接
connection.query(sql, params, function (err, result) { // 進(jìn)行查詢
if (!err){ // 如果過程沒有出錯(cuò)
success(result)
} else {
console.log(err)
}
})
connection.end() // 查詢完畢一定要關(guān)閉數(shù)據(jù)庫的連接
}
module.exports.dosomething = dosomething // 將此方法導(dǎo)出,供 web 層使用
至此暖璧, 文件夾說明完畢案怯。
回顧整個(gè)流程。
使用 express
開啟一個(gè)服務(wù)澎办。
使用 app.get, app.post
等待對應(yīng)的請求進(jìn)來嘲碱。
請求進(jìn)來之后, 使用loader.get()
拿到對應(yīng)的處理方法局蚀。這個(gè)方法去查詢數(shù)據(jù)庫麦锯, 邏輯復(fù)雜的還要經(jīng)過邏輯處理流程, 查詢完畢之后執(zhí)行loader
預(yù)先設(shè)置到的回調(diào)函數(shù)琅绅, 這個(gè)回調(diào)函數(shù)返回給客戶端需要的數(shù)據(jù)眶明。