@
一、系統模塊http -- 創建web服務端
http 模塊 是 Node.js 官方提供的、用來 創建 web 服務器 的模塊。
不需要使用 IIS、Apache 等這些第三方 web 服務器軟件,可直接通過 http 模塊提供的 http.createServer()
方法,就能方便的把一台普通的電腦,變成一台最基本的 Web 服務器,從而對外提供 Web 資源服務。
//app.js
// 1. 引用http系統模塊
const http = require('http');
// 2. http.createSercer(): 創建web服務器
const server = http.createServer();
// 3. 為服務器實例綁定 request 事件
server.on('request', (req, res) => {
console.log('someone visit my web server')
})
// 4. 啟動服務器
// Server.listen(端口號, callback):監聽端口,網站服務器必須監聽端口,否者無法向外服務
server.listen(3000, () => {
console.log('服務器已啟動,監聽3000端口,請訪問 localhost:3000')
});
之后通過命令行的方式開啟服務器端node app.js
二、NodeJS服務端接收並處理客戶端請求
server.on('requeset', function(req, res){})
在服務器創建成功后,調用通過 on()
為服務器注冊的 request
事件 並綁定處理函數,函數中可傳入兩個參數
其中參數 req
表示 客戶端請求相關的數據或屬性
另一個參數 res
表示 服務器響應相關的數據或屬性
舉例:
// 通過 on 方式 添加 請求事件 request, 后面函數為事件綁定函數, 當客戶端發送請求到服務端就執行該函數;
/*
req : 代表請求對象,該對象保存了請求相關的信息
res : 代表響應對象, 對客戶端的請求進行響應
*/
server.on('request', (req, res) => {
//req.method : 獲取請求方式
console.log(req.method);
//req.url : 獲取請求地址
console.log(req.url);
//req.headers : 獲取請求報文
console.log(req.headers);
/*
res.writedHead(parms1, parms2): 設置響應報文
parms1: 設置響應頭中的 http狀態碼, Number
parms2: 設置響應頭中的頭部字段, object
注意:res.writedHead() 需要在 res.end() 之前調用才有效
*/
res.writeHead(200, {
//指定響應頭中Content-Type字段值,值為響應內容類型,指定字符編碼以免亂碼
'Content-Type': 'text/html;charset=utf8'
});
//res.end() : 根據請求響應客戶端
res.end('這是服務端響應給客戶端頁面的內容');
});
③ 解決中文亂碼問題
當調用 res.end()
方法,向客戶端發送中文內容的時候,會出現亂碼問題,此時,需要手動設置內容的編碼格式:
server.on('request', (req, res) => {
// 響應內容包含中文
const str = `您的請求的 url 地址是 ${req.url}, 請求的 method 類型是 ${req.method}`;
// 為了防止顯示中文亂碼問題,需要設置響應頭 Content-Type 的值為 text/html; charset=utf-8
res.setHeader('Content-Type', 'text/html; charset=utf-8')
// 把包含中文的內容,響應給客戶端
res.end(str)
})
三、NodeJS 服務端處理請求參數
1. 系統模塊url -- 處理GET請求參數
get請求參數一般放置在瀏覽器地址欄中,例如:http://localhost:3000/?name=zhangsan&age=20
- 參數獲取需要借助系統模塊url,url模塊用來處理url地址
- 通過 url.parse() 來解析
req.url
地址,並更具第二參數判斷是否以對象的方式飯返回
//eg :在服務端接收到客戶端請求中的參數
const http = require('http');
// 導入url系統模塊 用於處理url地址
const url = require('url');
const app = http.createServer();
app.on('request', (req, res) => {
console.log(req.url);
console.log(url.parse(req.url, true));
// 將url路徑的各個部分解析出來並返回對象
// true 代表將參數解析為對象格式
let {query, pathname} = url.parse(req.url, true);
console.log(query);
console.log(pathname)
});
app.listen(1234);
2. 系統模塊querystring -- 處理POST請求參數
-
參數被放置在請求頭中發送到服務端
-
使用 querystring系統模塊 將post參數轉換為 對象格式
-
獲取POST參數需要使用
data
事件和end
事件
如果post參數數據量比較大,無法一次性發送完畢,則客戶端會把數據切割后,分批發送到服務器。所以 data
事件可能會觸發多次,每一次觸發 data 事件時,獲取到數據只是完整數據的一部分,需要手動對接收到的數據進行拼接;
當請求體數據接收完畢之后,會自動觸發 req 的 end
事件。
// 導入系統模塊querystring 用於將HTTP參數轉換為對象格式
const querystring = require('querystring');
app.on('request', (req, res) => {
//拼接post請求參數
let postData = '';
// post參數是通過事件的方式接受的
// 監聽參數傳輸事件, 當請求參數傳遞的時候出發data事件, params: post請求傳輸的數據
req.on('data', (params) => {
console.log(params)
postData += params
});
// 監聽參數傳輸完畢事件, 當參數傳遞完成的時候出發end事件
req.on('end', () => {
// 通過querystring模塊的parse方法解析 字符串參數postData 成對象格式並返回
console.log(postData )
console.log(querystring.parse(postData))
});
});
四、NodeJS服務端實現路由
1. 原生實現路由
路由是指客戶端請求地址與服務器端程序代碼的對應關系。簡單的說,就是請求什么響應什么,動態響應內容:
路由實現代碼
// 當客戶端發來請求的時候
app.on('request', (req, res) => {
// 獲取客戶端的請求路徑
let { pathname } = url.parse(req.url);
res.setHeader('Content-Type', 'text/html; charset=utf-8')
if (pathname == '/' || pathname == '/index') {
res.end('歡迎來到首頁');
} else if (pathname == '/list') {
res.end('歡迎來到列表頁頁');
} else {
res.end('抱歉, 您訪問的頁面出游了');
}
});
簡單案例:
const http = require('http');
const url = require('url');
const app = http.createServer();
const querystring = require("querystring");
app.on('request', (req, res) => {
let method = req.method.toLowerCase();
let path = url.parse(req.url);
let postparms = '';
res.writeHead(200, {
'Content-Type': 'text/html;charset=utf8'
})
if (method == "get") {
switch (path.pathname) {
case '/':
case '/index':
res.end('<h2>歡迎來到首頁<h2>');
break;
case '/list':
res.end('<h2>歡迎來到列表頁<h2>');
break;
case '/login':
res.end(`<h2>歡迎來到登錄界面</h2>
<form method="POST" action="http://localhost:1234/success">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit">
</form>
`);
break;
default:
res.end('<h2 style="color: red">您訪問的頁面不存在!<h2>');
}
} else if (method == "post") {
req.on('data', (parms) => {
postparms += parms;
})
req.on('end', () => {
postparms = querystring.parse(postparms);
let username = postparms.username;
let password = postparms.password;
switch (path.pathname) {
case '/success':
res.end("登錄成功!<br>您的用戶名為:" + username + "<br>您的密碼為" + password);
}
})
}
})
app.listen(1234);
console.log('服務器已啟動,監聽1234端口,請訪問 localhost:1234');
2. 第三方模塊 router
功能:實現路由
使用步驟:
- 獲取路由對象
- 調用路由對象提供的方法創建路由
- 啟用路由,使路由生效
//引入router第三方模塊並返回一個函數
const getRouter = require('router')
//通過調用getRouter()獲取路由對象router, 實際也是函數
const router = getRouter();
/*路由對象.get(參數1, 參數2)
功能:用來接收get請求
參數1:Url請求地址
參數2:當前請求處理函數,
req: 請求對象
res: 響應對象
*/
router.get('/add', (req, res) => {
res.end('Hello World!')
})
/*路由對象.post()
功能:用來接收post請求
參數:與get()一樣
*/
router.post('/',(req, res) => {
res.end();
})
/*
server: 由http模塊創建的服務器對象
通過給服務器對象添加請求事件捕獲請求並開啟路由功能
*/
server.on('request', (req, res) => {
/*
通過調用router()啟用路由功能,
router函數根據請求類型和請求地址自動匹配get()或post()
參數說明:
req:請求對象
res:響應對象
callback:當請求結束后會自動調用這個回調函數,它是必填參數
*/
router(req, res, () => {})
})
五、NodeJS服務端響應靜態資源
服務器端不需要處理,可以直接響應給客戶端的資源就是靜態資源,例如CSS、JavaScript、image文件。
① 第三方模塊 mime
app.on('request', (req, res) => {
// 獲取用戶的請求路徑
let pathname = url.parse(req.url).pathname;
pathname = pathname == '/' ? '/default.html' : pathname;
// 將用戶的請求路徑轉換為實際的服務器硬盤路徑, join方法可自動生成路徑鏈接符
let realPath = path.join(__dirname, 'public' + pathname);
//識別當前請求文件的文件類型
let type = mime.getType(realPath)
// 讀取文件
fs.readFile(realPath, (error, result) => {
// 如果文件讀取失敗
if (error != null) {
res.writeHead(404, {
'content-type': 'text/html;charset=utf8'
})
res.end('文件讀取失敗');
return;
}
res.writeHead(200, {
//根據類型,指定當前請求響應報文中的content-type,便於瀏覽器正確讀取文件格式
'content-type': type
})
res.end(result);
});
});
② 第三方模塊 serve-static
serve-static - npm (npmjs.com)
功能:實現靜態資源訪問服務
步驟:
- 引入serve-static模塊獲取創建靜態資源服務功能的方法
- 調用方法創建靜態資源服務並指定靜態資源服務目錄
- 啟用靜態資源服務功能
//導入第三方模塊'serve-static' , 並返回了一個方法
const serveStatic = require('serve-static')
/*調用返回的方法: serveStatic(參數1)
功能:實現靜態資源訪問服務功能
參數1:靜態資源文件目錄(絕對路徑)
返回值:一個方法
*/
const serve = serveStatic('public')
//server: 由http模塊創建的服務器對象
server.on('request', () => {
/*
啟用靜態資源服務
方法實現過程:根據請求對象來判斷當前請求是否訪問靜態資源,如果是靜態資源,它會把靜態資源直接響應給客戶端
callback: 請求結束后會自動調用回調函數,必填參數
*/
serve(req, res, callback);
})
server.listen(3000)