<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在09年Node.js
出來後,讓前端開發人員的開發路線變的不再那麼單調,經過這麼多年的發展,我們的開發基本已經離不開Node.js
,不管是用作於工具類的開發,還是做完伺服器端的中間層,Node.js
都佔據了非常重要的地位,今天我們就一起通過原生的js
+Node
來實現一個簡單的靜態資源服務,如果你還不瞭解這方面的知識,那就跟我一起來學習吧!
Node.js
經過這麼多年的發展,已經有了很多很優秀的基礎框架或類庫,像express.js
、Koa.js
、egg.js
等,它們都是基於原生的Node.js
來實現的,而我們之所以不選擇用這些框架,其實就是希望大家能夠了解前面這幾種框架是如何實現一個基礎的靜態資源服務的,只有當我們瞭解了這其中的知識點,再使用這些框架時才會更加得心應手,下面我們一起看一下這個基礎的靜態資源服務該如何開發吧!
首先,我們要了解的是,既然是要開發靜態資源服務,那麼什麼是靜態資源服務呢?簡單來說就是可以靜態存取的一個資源伺服器,而這些靜態資源包括但不限於類似html
、css
、js
以及一些圖片資源,音視訊等等。我們能通過網路直接存取這些內容,就是因為它們通過靜態資源伺服器將這些內容掛載在網上。
我們首先要做的就是建立一個服務,在Node
中我們通過http
模組來建立一個服務,http
是Node
中的一個基礎的API
,相關的內容可以查閱官方檔案,然後我們需要讀取原生的資源,那麼就需要用到另外一個模組fs
。fs
模組能夠操作原生的資原始檔,具體的內容也可以通過官網的檔案進行檢視,下面我們一起來看一下相關的程式碼,程式碼如下:
const fs = require('fs'); const http = require('http'); http.createServer((req, res) => { fs.readFile(__dirname + req.url, (err, data) => { if (err) { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('404: File not found'); } else { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); } }); }).listen(8000);
在上述的程式碼中,我們首先通過http.createServer
建立了一個伺服器,並且通過listen(8000)
來監聽了8000埠的服務,這樣我們就可以直接在瀏覽器中通過存取localhost:8000
來進行存取;在這個服務的內部,我們通過fs.readFile
方法來讀取檔案,因為我們沒有指定讀取的具體內容,而是通過獲取請求資訊來判斷我們要展示給使用者看到的內容,所以最終會在頁面中展示404
,如下圖所示:
上面的程式碼已經簡單了實現了一個靜態資源服務了,但是程式碼看起來就比較零散,下面我們一起來對這個程式碼進行改造,通過模組化的思想對程式碼進行升級,這樣不至於讓我們的程式碼看起來像麵條程式碼。
首先,我們讀取的檔案地址可能跟我們的這個檔案服務不在一個目錄中,為了解決問題問題,我們需要修改我們的檔案目錄,而關於目錄的相關資訊,就不得不用到Node
中另外一個很重要的模組path
了。通過path
模組,我們能夠解析不同目錄中的內容,一起來看一下修改後的程式碼吧,如下:
const fs = require('fs'); const path = require('path'); const directoryName = './public'; const requestUrl = 'index.html'; const filePath = path.join(directoryName, requestUrl); fs.readFile(filePath, (err, data) => { // ... });
我們通過path
將靜態資源的根目錄拼接在一起,這樣當我們使用fs.readFile
來讀取這個檔案時,不至於因為路徑錯誤而讀取不到正確的內容。
接下來我們需要考慮的就是安全性的問題了,因為我們不希望使用者能夠在未授權的情況隨意存取我們伺服器中的任意資源,目前並不是不能存取除了指定的目錄外的檔案,這就是一個安全性的問題。為了解決這個問題,我們可以通過path
模組來檢測使用者請求的檔案是否是可以存取的,下面一起看看我們對上述程式碼的改造,如下:
const path = require('path'); const directoryName = './public'; const root = path.normalize(path.resolve(directoryName)); const requestUrl = 'index.html'; const filePath = path.join(root, fileName); const isPathUnderRoot = path .normalize(path.resolve(filePath)) .startsWith(root);
上述程式碼中,我們通過path.normalize
來檢測這個檔案地址是否包含在根路徑中,這樣就能確保使用者只能存取到我們允許存取的地址。同樣的,我們還可以通過檢查檔案的型別來確保使用者無法存取到一些敏感的檔案。
為此,我們需要指定能夠存取的檔案型別的陣列或物件,只有當用戶存取的檔案在這個陣列或者物件中,才能展示給使用者看到,因此我們還需要用到path
模組來檢查檔案的字尾名,修改後程式碼如下:
const path = require('path'); const types = ['html', 'css', 'js', 'json']; const requestUrl = 'index.html'; const extension = path.extname(requestUrl).slice(1); const isTypeSupported = types.includes(extension);
我們定義了一個檔案型別的陣列,其中就包含了使用者可以存取的資源型別,然後我們通過path.extname
來檢測使用者請求的檔案的字尾,只有在這個型別檔案的陣列包含的型別,才會展示給使用者進行檢視。
當然,當我們存取html
的時候,我們一般都不會也不需要在瀏覽器中輸入xxx.html
這樣的字尾,因此我們還需要對html
這樣的字尾做省略,讓使用者可以直接通過網址就能存取正確的頁碼,而不需要新增.html
。下面我們一起看一下改造後的程式碼,如下:
const fs = require('fs'); const path = require('path'); const directoryName = './public'; const root = path.normalize(path.resolve(directoryName)); const extension = path.extname(req.url).slice(1); let fileName = requestUrl; if (requestUrl === '/') { fileName = 'index.html'; } else if (!extension) { try { fs.accessSync(path.join(root, requestUrl + '.html'), fs.constants.F_OK); fileName = requestUrl + '.html'; } catch (e) { fileName = path.join(requestUrl, 'index.html'); } }
上述的程式碼中,我們通過判斷使用者存取的檔案型別是否包含在前面的陣列中,當用戶存取的型別不包含時,我們通過fs.accessSync
來測試使用者存取的檔案是否是允許存取的,如果允許存取則直接返回一個.html
的檔案,如果使用者存取的地址是不允許存取的,則直接返回index.html
。
最後,當我們將前面所有的內容都完成後,我們可以將這些內容都整合在一起,下面我們一起來看一下最終完成的這個靜態資源服務的完整程式碼吧,如下:
const fs = require('fs'); const http = require('http'); const path = require('path'); // 靜態資源伺服器地址 const port = 8000; // 靜態資原始檔夾 const directoryName = './public'; // 允許存取的檔案型別 const types = { html: 'text/html', css: 'text/css', js: 'application/javascript', png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', json: 'application/json', xml: 'application/xml', }; // 靜態資原始檔根路徑 const root = path.normalize(path.resolve(directoryName)); // 建立靜態資源伺服器 const server = http.createServer((req, res) => { // 獲取存取的檔案型別 const extension = path.extname(req.url).slice(1); // 檔案型別字尾 const type = extension ? types[extension] : types.html; // 是否支援的檔案型別 const supportedExtension = Boolean(type); // 如果這個檔案型別不允許存取,則直接返回404 if (!supportedExtension) { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('404: File not found'); return; } // 通過url獲取存取的檔名稱 let fileName = req.url; // 如果存取的路徑是 / if (req.url === '/') { // 則檔名是 index.html fileName = 'index.html'; } else if (!extension) { try { // 檢測檔案是否允許存取 fs.accessSync(path.join(root, req.url + '.html'), fs.constants.F_OK); // 當允許存取時,則返回對應的頁面 fileName = req.url + '.html'; } catch (e) { // 否則直接返回 index.html fileName = path.join(req.url, 'index.html'); } } const filePath = path.join(root, fileName); const isPathUnderRoot = path.normalize(path.resolve(filePath)).startsWith(root); if (!isPathUnderRoot) { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('404: File not found'); return; } fs.readFile(filePath, (err, data) => { if (err) { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('404: File not found'); } else { res.writeHead(200, { 'Content-Type': type }); res.end(data); } }); }); server.listen(port, () => { console.log(`Server is listening on port ${port}`); });
最終我們通過不到100行的程式碼就實現了這個靜態資源服務,我們可以看一下具體的執行效果。
當我們存取首頁時,就直接展示預設的index.html
中的檔案,如果我們存取的內容不允許存取,則直接顯示404
,如下所示:
我們只通過Node.js
中一些簡單的API就開發了一個基礎的靜態資源伺服器,也讓大家瞭解了一些Node.js
相關的基礎操作,瞭解這些基礎的操作不僅有利於提高我們自身的知識儲備,也更有利於我們在實際開發中少踩一些坑。
以上就是Node.js開發靜態資源伺服器的詳細內容,更多關於Node.js靜態資源伺服器的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45