Express中間件是在請求和響應(yīng)之間執(zhí)行的函數(shù),它可以訪問請求對象(req)、響應(yīng)對象(res)和應(yīng)用程序中的下一個中間件函數(shù)(通常命名為next)。中間件函數(shù)可以執(zhí)行各種任務(wù),例如修改請求和響應(yīng)對象、執(zhí)行身份驗證、記錄請求信息、處理錯誤等。Express中間件是構(gòu)建強(qiáng)大Web應(yīng)用程序的關(guān)鍵組件之一。以下是關(guān)于Express中間件的介紹:
Express提供了一些內(nèi)置的中間件函數(shù),用于執(zhí)行常見的任務(wù),例如處理JSON、URL編碼和靜態(tài)文件。你可以通過調(diào)用app.use()方法來使用這些內(nèi)置中間件。
你還可以編寫自定義中間件來執(zhí)行特定的任務(wù)。自定義中間件函數(shù)采用三個參數(shù):req(請求對象)、res(響應(yīng)對象)和next(調(diào)用下一個中間件函數(shù)的函數(shù))。你可以將自定義中間件函數(shù)添加到Express應(yīng)用程序中,以便在請求處理流程中使用它們。
javascript復(fù)制代碼app.use((req, res, next)=> {
// 在請求到達(dá)時執(zhí)行的任務(wù)
console.log('Middleware executed');
next(); // 調(diào)用下一個中間件函數(shù)
});
除了內(nèi)置的和自定義的中間件之外,Express 社區(qū)提供了許多第三方中間件,可以用于處理各種任務(wù),如身份驗證、日志記錄、跨域請求等。你可以通過 npm 安裝這些中間件并將它們集成到你的 Express 應(yīng)用程序中。例如:
bash
復(fù)制代碼npm install helmet
然后在應(yīng)用程序中使用:
javascript復(fù)制代碼const helmet=require('helmet');
app.use(helmet());
在 Express 應(yīng)用程序中,中間件的順序非常重要。中間件的順序決定了它們被執(zhí)行的順序。通常,你應(yīng)該先使用那些處理請求的中間件,然后才是處理響應(yīng)的中間件。例如,使用 express.json() 和 express.urlencoded() 中間件來解析請求體應(yīng)該放在路由處理程序之前。
Express還允許你定義專門用于處理錯誤的中間件。錯誤處理中間件函數(shù)采用四個參數(shù):err(錯誤對象)、req(請求對象)、res(響應(yīng)對象)和next(調(diào)用下一個中間件函數(shù)的函數(shù))。你可以在應(yīng)用程序中定義一個或多個錯誤處理中間件來捕獲并處理在請求處理過程中發(fā)生的錯誤。
javascript復(fù)制代碼app.use((err, req, res, next)=> {
// 錯誤處理邏輯
console.error(err);
res.status(500).send('Internal Server Error');
});
除了應(yīng)用級中間件,Express還支持路由級中間件。這些中間件與特定路由相關(guān)聯(lián),只在匹配該路由時才會執(zhí)行。
javascript復(fù)制代碼const router=express.Router();
router.use((req, res, next)=> {
// 路由級中間件邏輯
next();
});
router.get('/', (req, res)=> {
res.send('Hello from router');
});
app.use('/api', router);
在Express中,你可以將多個中間件函數(shù)鏈接在一起形成中間件鏈。這些中間件函數(shù)按照它們添加到鏈中的順序依次執(zhí)行。你還可以使用app.use()來組合多個中間件函數(shù),使它們在應(yīng)用程序的所有路由中都得到執(zhí)行。
javascript復(fù)制代碼app.use(middleware1);
app.use('/api', middleware2);
app.use(middleware3);
中間件函數(shù)可以是同步的,也可以是異步的。如果中間件函數(shù)執(zhí)行異步操作(如訪問數(shù)據(jù)庫或調(diào)用外部API),則應(yīng)該在函數(shù)體內(nèi)使用async關(guān)鍵字,并且要么在函數(shù)體內(nèi)使用await關(guān)鍵字等待異步操作完成,要么返回一個Promise。
javascript復(fù)制代碼app.use(async (req, res, next)=> {
try {
await someAsyncOperation();
next();
} catch (err) {
next(err);
}
});
通過充分了解和靈活使用Express中間件的類型、作用、用法和執(zhí)行順序,開發(fā)者可以更好地構(gòu)建靈活、高效的Node.js應(yīng)用程序。中間件提供了一個強(qiáng)大的工具集,可以幫助開發(fā)者處理各種請求、執(zhí)行各種任務(wù),并確保應(yīng)用程序的性能和可維護(hù)性。因此,深入學(xué)習(xí)和掌握Express中間件是構(gòu)建出色Node.js應(yīng)用程序的關(guān)鍵之一。
比Python,JavaScript才是更適合寫爬蟲的語言。原因有如下三個方面:
一、任務(wù):爬取用戶在Github上的repo信息
通過實例的方式學(xué)習(xí)爬蟲是最好的方法,先定一個小目標(biāo):爬取github repo信息。入口URL如下,我們只需要一直點擊next按鈕就能夠遍歷到用戶的所有repo。
https://github.com/{{username}}?tab=repositories
獲取repo之后,可以做什么?
二、爬蟲雙股劍:axios和jQuery
axios是JavaScript中很常用的異步網(wǎng)絡(luò)請求庫,相比jQuery,它更輕量、更專業(yè)。既能夠用于瀏覽器端,也可以用于Node。它的語法風(fēng)格是promise形式的。在本任務(wù)中,只需要了解如下用法就足夠了:
axios.get(url).then((resp)=> { 請求成功,處理resp.data中的html數(shù)據(jù) }).catch((err)=> { 請求失敗,錯誤處理 })
請求之后需要處理回復(fù)結(jié)果,處理回復(fù)結(jié)果的庫當(dāng)然是用jQuery。實際上,我們有更好的選擇:cheerio。
在node下,使用jQuery,需要使用jsdom庫模擬一個window對象,這種方法效率較低,四個字形容就是:笨重穩(wěn)妥。
如下代碼使用jQuery解析haha.html文件
fs=require("fs") jquery=require('jquery') jsdom=require('jsdom') //fs.readFileSync()返回結(jié)果是一個buffer,相當(dāng)于byte[] html=fs.readFileSync('haha.html').toString('utf8') dom=new jsdom.JSDOM(html) $=jquery(dom.window) console.log($('h1'))
cheerio只實現(xiàn)了jQuery中的DOM部分,相當(dāng)于jQuery的一個子集。cheerio的語法和jQuery完全一致,在使用cheerio時,幾乎感覺不到它和jQuery的差異。在解析HTML方面,毫無疑問,cheerio是更好的選擇。如下代碼使用cheerio解析haha.html文件。
cheerio=require('cheerio') html=require('fs').readFileSync("haha.html").toString('utf8') $=cheerio.load(html) console.log($('h1'))
只需20余行,便可實現(xiàn)簡單的github爬蟲,此爬蟲只爬取了一頁repo列表。
var axios=require("axios") var cheerio=require("cheerio") axios.get("https://github.com/weiyinfu?tab=repositories").then(resp=> { var $=cheerio.load(resp.data) var lis=$("#user-repositories-list li") var repos=[] for (var i=0; i < lis.length; i++) { var li=lis.eq(i) var repo={ repoName: li.find("h3").text().trim(), repoUrl: li.find("h3 a").attr("href").trim(), repoDesc: li.find("p").text().trim(), language: li.find("[itemprop=programmingLanguage]").text().trim(), star: li.find(".muted-link.mr-3").eq(0).text().trim(), fork: li.find(".muted-link.mr-3").eq(1).text().trim(), forkedFrom: li.find(".f6.text-gray.mb-1 a").text().trim() } repos.push(repo) } console.log(repos) })
三、更豐富的功能
爬蟲不是目的,而是達(dá)成目的的一種手段。獲取數(shù)據(jù)也不是目的,從數(shù)據(jù)中提取統(tǒng)計信息并呈現(xiàn)給人才是最終目的。
在github爬蟲的基礎(chǔ)上,我們可以擴(kuò)展出更加豐富的功能:使用echarts等圖表展示結(jié)果。
要想讓更多人使用此爬蟲工具獲取自己的github統(tǒng)計信息,就需要將做成一個網(wǎng)站的形式,通過搜索頁面輸入用戶名,啟動爬蟲立即爬取github信息,然后使用echarts進(jìn)行統(tǒng)計展示。網(wǎng)站肯定也要用js作為后端,這樣才能和js爬蟲無縫銜接,不然還要考慮跨語言調(diào)用。js后端有兩大web框架express和koa,二者API非常相似,并無優(yōu)劣之分,但express更加流行。
如上設(shè)計有一處用戶體驗不佳的地方:當(dāng)啟動爬蟲爬取github信息時,用戶可能需要等待好幾秒,這個過程不能讓用戶干等著。一種解決思路是:讓用戶看到爬蟲爬取的進(jìn)度或者爬取過程。可以通過websocket向用戶推送爬取過程信息并在前端進(jìn)行展示。展示時,使用類似控制臺的界面進(jìn)行展示。
如何存儲爬取到的數(shù)據(jù)呢?使用MongoDB或者文件都可以,最好實現(xiàn)兩種存儲方式,讓系統(tǒng)的存儲方式變得可配置。使用MongoDB時,用到j(luò)s中的連接池框架generic-pool。
整個項目用到的庫包括:
試用地址:
https://weiyinfu.cn/githubstatistic/search.html?
案例地址:https://github.com/weiyinfu/GithubStatistic
原文鏈接:https://zhuanlan.zhihu.com/p/53763115
xpress框架是Node.js基金會的一個項目,官方網(wǎng)址為http://expressjs.com。(中文網(wǎng)站為http://expressjs.com/zh-cn)。它提供了對Node.js原生API比較好的封裝,從而使開發(fā)者更容易的使用Node.js,并用來開發(fā)強(qiáng)壯的Web、移動應(yīng)用,以及API的一些其他功能。開發(fā)人員還能夠方便的為它開發(fā)插件和擴(kuò)展,從而增加Express的能力。
簡言之,Express 是一個簡潔而靈活的 node.js Web應(yīng)用框架, 提供了一系列強(qiáng)大特性幫助你創(chuàng)建各種 Web 應(yīng)用,和豐富的 HTTP 工具。使用 Express 可以快速地搭建一個完整功能的網(wǎng)站。
通過使用Node Express,可以使用更少的代碼來實現(xiàn)功能。至少通過使用Node Express可以實現(xiàn)中間件來響應(yīng)http請求,可以定義路由表來定義不同請求的響應(yīng)函數(shù),還可以使用模板引擎來輸出html頁面。其實這也是Express的核心特點。
Express 框架核心特性:
可以設(shè)置中間件來響應(yīng) HTTP 請求。
定義了路由表用于執(zhí)行不同的 HTTP 請求動作。
可以通過向模板傳遞參數(shù)來動態(tài)渲染 HTML 頁面。
好,接下來我們進(jìn)行Express的安裝,我們通過以下命令就可以安裝 Express 并將其保存到依賴列表中:
npm install express --save
上命令會將 Express 框架安裝在當(dāng)前目錄的 node_modules 目錄中, node_modules 目錄下會自動創(chuàng)建 express 目錄。以下幾個重要的模塊是需要與 express 框架一起安裝的:
body-parser - node.js 中間件,用于處理 JSON, Raw, Text 和 URL 編碼的數(shù)據(jù)。
cookie-parser - 這就是一個解析Cookie的工具。通過req.cookies可以取到傳過來的cookie,并把它們轉(zhuǎn)成對象。
multer - node.js 中間件,用于處理 enctype="multipart/form-data"(設(shè)置表單的MIME編碼)的表單數(shù)據(jù)。
npm install body-parser --save
npm install cookie-parser --save
npm install multer --save
安裝完后,我們可以通過以下npm命令查看 express 使用的版本號:
npm list express
如果小伙伴們進(jìn)行到了上一步驟,說明我們已經(jīng)把Express安裝成功了。接下來,我們就可以學(xué)習(xí)Express和使用它進(jìn)行一個實例的開發(fā)。哈哈,廢話不多說,第一個實例想都不用想,就是用Express框架來輸出Hello World。
以下實例的需求呢就是,我們新建一個demo.js文件,在文件我們需要引入express模塊,并在客戶端發(fā)起請求后,響應(yīng)“Hello World”字符串。
創(chuàng)建demo.js文件,代碼如下所示:
上面代碼寫完之后,我們開始運行,程序運行起來,通過訪問http://localhost:3000/
就可以看到字符串“Hello World”
接下來,我們看看Express是如何處理請求和響應(yīng)的。
Express 應(yīng)用使用回調(diào)函數(shù)的參數(shù): request 和 response 對象來處理請求和響應(yīng)的數(shù)據(jù)。
app.get('/', function (req, res) {
// --})
request 和 response 對象的具體介紹:
Request 對象 - request 對象表示 HTTP 請求,包含了請求查詢字符串,參數(shù),內(nèi)容,HTTP 頭部等屬性。常見屬性有:
1.req.app:當(dāng)callback為外部文件時,用req.app訪問express的實例
2.req.baseUrl:獲取路由當(dāng)前安裝的URL路徑
3.req.body / req.cookies:獲得「請求主體」/ Cookies
4.req.fresh / req.stale:判斷請求是否還「新鮮」
5.req.hostname / req.ip:獲取主機(jī)名和IP地址
6.req.originalUrl:獲取原始請求URL
7.req.params:獲取路由的parameters
8.req.path:獲取請求路徑
9.req.protocol:獲取協(xié)議類型
10.req.query:獲取URL的查詢參數(shù)串
11.req.route:獲取當(dāng)前匹配的路由
12.req.subdomains:獲取子域名
13.req.accepts():檢查可接受的請求的文檔類型
14.req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一個可接受字符編碼
15.req.get():獲取指定的HTTP請求頭
16.req.is():判斷請求頭Content-Type的MIME類型
Response 對象 - response 對象表示 HTTP 響應(yīng),即在接收到請求時向客戶端發(fā)送的 HTTP 響應(yīng)數(shù)據(jù)。常見屬性有:
1.res.app:同req.app一樣
2.res.append():追加指定HTTP頭
3.res.set()在res.append()后將重置之前設(shè)置的頭
4.res.cookie(name,value [,option]):設(shè)置Cookie
5.opition: domain / expires / httpOnly / maxAge / path / secure / signed
6.res.clearCookie():清除Cookie
7.res.download():傳送指定路徑的文件
8.res.get():返回指定的HTTP頭
9.res.json():傳送JSON響應(yīng)
10.res.jsonp():傳送JSONP響應(yīng)
11.res.location():只設(shè)置響應(yīng)的Location HTTP頭,不設(shè)置狀態(tài)碼或者close response
12.res.redirect():設(shè)置響應(yīng)的Location HTTP頭,并且設(shè)置狀態(tài)碼302
13.res.render(view,[locals],callback):渲染一個view,同時向callback傳遞渲染后的字符串,如果在渲染過程中有錯誤發(fā)生next(err)將會被自動調(diào)用。callback將會被傳入一個可能發(fā)生的錯誤以及渲染后的頁面,這樣就不會自動輸出了。
14.res.send():傳送HTTP響應(yīng)
15.res.sendFile(path [,options] [,fn]):傳送指定路徑的文件 -會自動根據(jù)文件extension設(shè)定Content-Type
16.res.set():設(shè)置HTTP頭,傳入object可以一次設(shè)置多個頭
17.res.status():設(shè)置HTTP狀態(tài)碼
18.res.type():設(shè)置Content-Type的MIME類型
今天小編就把Express框架先介紹到這里吧。其實呢,Express框架還有很多核心功能,例如其中的路由、處理靜態(tài)文件、處理get請求、post請求等等功能,這寫功能的使用,我們將會在下期在一一介紹,我們下期再見。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。