前言
十余年的商州網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。網(wǎng)絡(luò)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整商州建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)從事“商州網(wǎng)站設(shè)計”,“商州網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。
在 NodeJS 中用來創(chuàng)建服務(wù)的模塊是 http 核心模塊,本篇就來介紹關(guān)于使用 http 模塊搭建 HTTP 服務(wù)器和客戶端的方法,以及模塊的基本 API。
HTTP 服務(wù)器
1、創(chuàng)建 HTTP 服務(wù)器
在 NodeJS 中,創(chuàng)建 HTTP 服務(wù)器可以與 net 模塊創(chuàng)建 TCP 服務(wù)器對比,創(chuàng)建服務(wù)器有也兩種方式。
方式 1:
const http = require("http"); const server = http.createServer(function(req, res) { // ...... }); server.listen(3000);
方式 2:
const http = require("http"); const server = http.createServer(); server.on("request", function(req, res) { // ...... }); server.listen(3000);
在 createServer 的回調(diào)和 request 事件的回調(diào)函數(shù)中有兩個參數(shù),req(請求)、res(響應(yīng)),基于 socket,這兩個對象都是 Duplex 類型的可讀可寫流。
http 模塊是基于 net 模塊實現(xiàn)的,所以 net 模塊原有的事件在 http 中依然存在。
const http = require("http"); const server = http.createServer(); // net 模塊事件 server.on("connection", function(socket) { console.log("連接成功"); }); server.listen(3000);
2、獲取請求信息
在請求對象 req 中存在請求的方法、請求的 url(包含參數(shù),即查詢字符串)、當(dāng)前的 HTTP 協(xié)議版本和請求頭等信息。
const http = require("http"); const server = http.createServer(); server.on("request", function(req, res) { console.log(req.method); // 獲取請求方法 console.log(req.url); // 獲取請求路徑(包含查詢字符串) console.log(req.httpVersion); // 獲取 HTTP 協(xié)議版本 console.log(req.headers); // 獲取請求頭(對象) // 獲取請求體的內(nèi)容 let arr = []; req.on("data", function(data) { arr.push(data); }); req.on("end", function() { console.log(Buffer.concat(arr).toString()); }); }); server.listen(3000, function() { console.log("server start 3000"); });
通過 req 對應(yīng)的屬性可以拿到請求行和請求首部的信息,請求體內(nèi)的內(nèi)容通過流操作來獲取,其中 url 中存在多個有用的參數(shù),我們自己處理會很麻煩,可以通過 NodeJS 的核心模塊 url 進(jìn)行解析。
const url = require("url"); let str = "http://user:pass@www.pandashen.com:8080/src/index.html?a=1&b=2#hash"; // parse 方法幫助我們解析 url 路徑 let obj = url.parse(str, true); console.log(obj); // { // protocol: 'http:', // slashes: true, // auth: 'user:pas', // host: 'www.pandashen.com:8080', // port: '8080', // hostname: 'www.pandashen.com', // hash: '#hash', // search: '?a=1&b=2', // query: '{ a: '1', b: '2' }', // pathname: '/src/index.html' // path: '/src/index.html?a=1&b=2', // href: 'http://user:pass@www.pandashen.com:8080/src/index.html?a=1&b=2#hash' }
在被解析路徑返回的對象中有幾個屬性被經(jīng)常使用:
我們使用 url 的 parse 方法來幫我們解析請求路徑,在真實的服務(wù)器中傳入的第一個參數(shù)為 req.url,第二個參數(shù)不傳時,query 會被解析成 a=1&b=2 的形式,第二個參數(shù)傳入 true,query 屬性的查詢字符串會被解析成對象的形式。
url 模塊中,將查詢字符串 a=1&b=2 轉(zhuǎn)換為對象 { a: '1', b: '2' } 的實現(xiàn)方式其實是使用正則替換實現(xiàn)的。
模擬查詢字符串轉(zhuǎn)換對象的核心邏輯:
let str = "a=1&b=2&c=3"; let obj = {}; str.replace(/([^=&]+)=([^=&]+)/g, function() { obj[arguments[1]] = arguments[2]; }); console.log(obj); // { a: '1', b: '2', c: '3' }
在上面代碼的 replace 方法的回調(diào)函數(shù)中參數(shù)集合的第一項為匹配到的字符串,第二項為第一個分組的值,第三項為第二個分組的值,依次類推,倒數(shù)第二項為分組匹配的索引,最后一項為原字符串。
3、設(shè)置響應(yīng)信息
我們可以通過 req 來獲取請求信息,自然也可以通過 res 來設(shè)置響應(yīng)信息返回給客戶端。
const http = require("http"); const server = http.createServer(); server.on("request", function(req, res) { // 設(shè)置響應(yīng)頭(過去的用法),不能多次調(diào)用,見到要認(rèn)識 res.writeHead(200, { "Content-Type": "text", a: "hello world" }); // 設(shè)置響應(yīng)頭(現(xiàn)在的用法,常用),可以多次調(diào)用,每次設(shè)置一個響應(yīng)頭 res.setHeader("Content-Type", "text"); // 設(shè)置狀態(tài)碼,不設(shè)置默認(rèn)為 200 res.statusCode = 200; // 不發(fā)送 Date(日期)響應(yīng)頭 res.sendDate = false; // 返回內(nèi)容 res.write("hello world"); // 不會關(guān)閉連接 res.end("hello world"); // 將內(nèi)容返回后關(guān)閉連接 }); server.listen(3000, function() { console.log("server start 3000"); });
返回給客戶端的信息主要分為兩部分,分別為響應(yīng)頭和返回給瀏覽器的內(nèi)容,在不設(shè)置響應(yīng)頭的情況下,默認(rèn)會設(shè)置響應(yīng)頭 Content-Length 和 Date ,代表當(dāng)前返回給客戶端的內(nèi)容長度和日期。
返回給瀏覽器的內(nèi)容可以通過 res 的 write 方法和 end 方法進(jìn)行發(fā)送,write 方法不會斷開連接(通常在響應(yīng)后需要斷開與客戶端的連接),end 方法會斷開連接,在 end 方法存在參數(shù)時,會在內(nèi)部調(diào)用 write 將參數(shù)內(nèi)容返回給客戶端,并斷開連接。
HTTP 客戶端
在 net 模塊中可以通過 net.createConnection 來創(chuàng)建客戶端,并發(fā)送請求到服務(wù)端,在 http 模塊同樣可以創(chuàng)建客戶端,并向 http 服務(wù)器發(fā)送請求。
// 客戶端:client.js const http = require("http"); // 發(fā)送請求的配置 let config = { host: "localhost", port: 3000, method: "get", headers: { a: 1 } }; // 創(chuàng)建客戶端 let client = http.request(config, function(res) { // 接收服務(wù)端返回的數(shù)據(jù) let arr = []; res.on("data", function(data) { arr.push(data); }); res.on("end", function() { console.log(Buffer.concat(arr).toString()); }); }); // 發(fā)送請求 client.end();
在 http 模塊中通過 request 方法創(chuàng)建客戶端,該方法第一個參數(shù)為發(fā)送請求的配置,包含請求地址、端口號、請求方法以及請求頭等,第二個參數(shù)為回調(diào)函數(shù),在請求被響應(yīng)后執(zhí)行,回調(diào)函數(shù)的參數(shù)為服務(wù)器的響應(yīng)對象 res,創(chuàng)建的客戶端通過 end 方法將請求發(fā)出與服務(wù)端進(jìn)行通信。
使用 NodeJS 實現(xiàn)的 “爬蟲” 其實就可以通過 http 模塊創(chuàng)建的客戶端來實現(xiàn),客戶端幫我們向我們要抓取數(shù)據(jù)的地址發(fā)送請求,并拿到響應(yīng)的數(shù)據(jù)進(jìn)行解析。
同時使用 HTTP 客戶端和服務(wù)器
我們使用自己創(chuàng)建的客戶端訪問自己的服務(wù)端,并體會請求響應(yīng)的過程,就是用上面 client.js 作為客戶端,啟動 server.js 后再啟動 client.js 查看效果。
// 服務(wù)器:server.js const http = require("http"); http.createServer(function(req, res) { console.log("The request came"); // 獲取客戶端請求信息 console.log(req.method); console.log(req.headers); // 返回數(shù)據(jù) res.write("hello world"); }).listen(3000, function() { console.log("server start 3000"); });
簡易爬蟲
我們結(jié)合 http 模塊創(chuàng)建的服務(wù)端和客戶端實現(xiàn)一個簡易版的 “爬蟲” 去抓取百度新聞頁所有 li 標(biāo)簽內(nèi)的文章標(biāo)題。
// 簡易爬蟲:crawl.js const http = require("http"); // 創(chuàng)建服務(wù)器 const server = http.createServer(); // 監(jiān)聽請求 server.on("request", function(req, res) { let client = http.request( { host: "news.baidu.com", method: "get", port: 80 }, function(r) { // 接收百度新聞返回的數(shù)據(jù) let arr = []; r.on("data", function(data) { arr.push(data); }); r.on("end", function() { // 處理數(shù)據(jù) let result = Buffer.concat(arr).toString(); let matches = result.match(/
上面的正則匹配中 ([\s\S*?]) 代表匹配
上面爬取百度新聞數(shù)據(jù)的過程中,我們自己的 Node 服務(wù)器扮演了一個 “中間層” 的角色,我們通過瀏覽器訪問自己的服務(wù)器 localhost:3000 觸發(fā) request 事件,執(zhí)行了回調(diào),在回調(diào)中創(chuàng)建客戶端向 news.baidu.com 發(fā)送了請求,并在客戶端的回調(diào)中處理了響應(yīng)(百度新聞頁返回的數(shù)據(jù)),將處理后的內(nèi)容通過我們自己 Node 服務(wù)器的 res 對象返回給了瀏覽器。
總結(jié)
相信在讀過本篇文章之后對搭建一個 Node 服務(wù)應(yīng)該已經(jīng)有了思路,為未來通過 Node 服務(wù)實現(xiàn)復(fù)雜的業(yè)務(wù)場景及數(shù)據(jù)的處理打下了一個基礎(chǔ),希望初學(xué) Node 的小伙伴在看了這篇文章后能有所收獲。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。