[Nodejs] node實現靜態檔案伺服器
node 靜態檔案處理
一般後端進行靜態檔案處理都是使用 Apache nginx 等靜態 web 伺服器,但是既然使用 node 了,就用 node 實現以下靜態伺服器吧.
之前弄了不少充滿藝術的資料,就弄個頁面進行藝術欣賞吧
app.js
"/": (request, response) => { response.writeHead(200, { "content-type": "text/html;charset=utf-8" }); let stream = fs.createReadStream( path.join(__dirname, "/views/index.html") ); stream.on("error", function() { response.writeHead(500, { "content-type": "text/html;charset=utf-8" }); response.end("<h1>500 Server Error</h1>"); }); stream.pipe(response); },
views/index.html/index.js/index.css
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>時尚風範</title> <link rel="stylesheet" href="./index.css" type="text/css" /> <script src="./index.js"></script> </head> <body> <div class="img-list"> <div class="header">我是寫真集</header> </div> </body> </html>
但是開啟之後什麼都不能看,css 和 js 在控制檯都是 404 顯示.因為伺服器沒有寫相應的程式碼去處理這些檔案,所以接收到請求,伺服器也是一臉茫然,不知道究竟要幹什麼.
所有我們要對請求的資源做出相對應的回答,那怕是個 404
新增 css 和 js 的支援
"/index.css": (request, response) => { response.writeHead(200, { "content-type": "text/css;chartset=utf-8" }); let stream = fs.createReadStream( path.join(__dirname, "/views/index.css") ); stream.on("error", function() { response.writeHead(500, { "content-type": "text/html;charset=utf-8" }); response.end("<h1>500 Server Error</h1>"); }); stream.pipe(response); }, "/index.js": (request, response) => { response.writeHead(200, { "content-type": "text/javasvript;chartset=utf-8" }); let stream = fs.createReadStream( path.join(__dirname, "/views/index.js") ); stream.on("error", function() { response.writeHead(500, { "content-type": "text/html;charset=utf-8" }); response.end("<h1>500 Server Error</h1>"); }); stream.pipe(response); },
這樣就正常的載入和執行 css 和 js 了,但是程式碼靈活性不夠,重複率太高.
靜態資源伺服器
區分路由
... if (pathname !== "/favicon.ico") { if (path.extname(pathname) === "") { router(pathname)(request, response); } else { assets(pathname)(request, response); } } ...
新增靜態資源處理
function assets(p) { let ext = path.extname(p); ext = ext ? ext.slice(1) : "unknown"; let contentType = getMime(ext); contentType += ";charset=utf-8"; let filePath; if (/image/.test(contentType)) { filePath = path.join(static_path, p); } else { filePath = path.join(public_path, p); } return async function(request, response) { try { let stats = await stat(filePath); if (stats && stats.isFile()) { readFile(response, filePath, contentType); } } catch (err) { console.log(err); } }; }
我們需要根據檔案型別做相應處理
對不同的檔案進行不同的響應頭處理
module.exports = { getMime: function(ext) { let mime = { css: "text/css", gif: "image/gif", html: "text/html", ico: "image/x-icon", jpeg: "image/jpeg", jpg: "image/jpeg", js: "text/javascript", json: "application/json", pdf: "application/pdf", png: "image/png", svg: "image/svg+xml", swf: "application/x-shockwave-flash", tiff: "image/tiff", txt: "text/plain", wav: "audio/x-wav", wma: "audio/x-ms-wma", wmv: "video/x-ms-wmv", xml: "text/xml" }; return mime[ext] || "text/plain"; } };
載入相應的靜態檔案
function readFile(response, filePath, contentType) { response.writeHead(200, { "content-type": contentType }); let stream = fs.createReadStream(filePath); stream.on("error", function() { response.writeHead(500, { "content-type": contentType }); response.end("<h1>500 Server Error</h1>"); }); stream.pipe(response); }
index.js
window.onload = function() { let path = "http://127.0.0.1:9527/mrw/%E5%B0%8F%E6%B2%AB%E7%90%B3%E3%80%8A%E8%8B%8F%E6%A2%85%E5%B2%9B%E6%97%85%E6%8B%8D%E5%86%99%E7%9C%9F%E3%80%8B%20[%E8%8A%B1%E3%81%AE%E9%A2%9CHuaYan]%20Vol.057%20%E5%86%99%E7%9C%9F%E9%9B%86/%E5%B0%8F%E6%B2%AB%E7%90%B3%E3%80%8A%E8%8B%8F%E6%A2%85%E5%B2%9B%E6%97%85%E6%8B%8D%E5%86%99%E7%9C%9F%E3%80%8B%20[%E8%8A%B1%E3%81%AE%E9%A2%9CHuaYan]%20Vol.057%20%E5%86%99%E7%9C%9F%E9%9B%86_image"; let suffix = ".jpg"; let content = document.createElement("div"); let body = document.getElementsByTagName("body")[0]; content.setAttribute("class", "content"); for (let i = 0; i < 56; i++) { let item = document.createElement("img"); item.setAttribute("src", `${path}${i}${suffix}`); content.appendChild(item); } body.appendChild(content); };
當然,正常的寫真集不是這樣做的,而是通過資料庫儲存硬碟路徑存放地址,然後返回給前端 url+path 的形式,路徑也不會這麼長.這裡只是處理靜態檔案.
Docs
- 常見的 MIME 型別
- fs 模組 -- JavaScript 標準參考教程(alpha)
-
宣告:僅供學習,不可用於商業用途