Pertama sekali, saya ingin mengucapkan terima kasih kepada github dan pengarang yang menyediakan kod sumber ini di github. Pelayan fail statik hari ini adalah lebih rumit sedikit daripada malam tadi, dan anda boleh mempelajari banyak perkara baharu.
Jika anda melihat dengan teliti, anda akan mendapati bahawa kod kali ini mempunyai fungsi fs.stat dan fungsi paip objek ReadStream Fungsi stat digunakan untuk mendapatkan maklumat fail. Parameter pertama ialah laluan fail yang dilalui, dan yang kedua ialah fungsi panggil balik Atribut statistik parameter kedua bagi fungsi panggil balik ialah maklumat asas fail. Fungsi paip digunakan untuk menyambungkan strim boleh dibaca ini ke strim boleh tulis destinasi Data yang dihantar ke strim ini akan ditulis ke strim destinasi. Strim sumber dan destinasi sentiasa disegerakkan dengan menjeda dan menyambung semula strim apabila perlu.
Peningkatan pelayan fail statik ini ialah penggunaan pengepala Last-Modified dan If-Modified-Sejak, yang menghapuskan keperluan untuk mengembalikan fail yang telah wujud kepada penyemak imbas. Ngomong-ngomong, sumber itu boleh dikembalikan kepada sumber untuk gzip atau mengempiskan pemampatan mengikut kaedah pemampatan sumber permintaan penyemak imbas.
var PORT = 8000; var http = require("http"); var url = require("url"); var fs = require("fs"); var path = require("path"); var mime = require("./mime").types; var config = require("./config"); var zlib = require("zlib"); var server = http.createServer(function(request, response) { response.setHeader("Server", "Node/V5"); var pathname = url.parse(request.url).pathname; console.log("url = " + pathname); if (pathname.slice(-1) === "/") { pathname = pathname + config.Welcome.file; } var realPath = __dirname + "/" + path.join("assets", path.normalize(pathname.replace(/\.\./g, ""))); console.log("realPath = " + realPath); var pathHandle = function (realPath) { fs.stat(realPath, function (err, stats) { if (err) { response.writeHead(404, "Not Found", {'Content-Type': 'text/plain'}); response.write("stats = " + stats); response.write("This request URL " + pathname + " was not found on this server."); response.end(); } else { if (stats.isDirectory()) { realPath = path.join(realPath, "/", config.Welcome.file); pathHandle(realPath); } else { var ext = path.extname(realPath); ext = ext ? ext.slice(1) : 'unknown'; var contentType = mime[ext] || "text/plain"; response.setHeader("Content-Type", contentType); //获得文件的修改时间 var lastModified = stats.mtime.toUTCString(); var ifModifiedSince = "If-Modified-Since".toLowerCase(); //设置Last-Modified //服务器给浏览器返回文件最后一次修改时间Last-Modified response.setHeader("Last-Modified", lastModified); if (ext.match(config.Expires.fileMatch)) { var expires = new Date(); expires.setTime(expires.getTime() + config.Expires.maxAge * 1000); response.setHeader("Expires", expires.toUTCString()); response.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge); } //服务器接收浏览器发送过来的If-Modified-Since报文头 //日期相同表示该资源没有变化则返回304 //告诉浏览器该资源你已经有了,不需要再请求了 if (request.headers[ifModifiedSince] && lastModified == request.headers[ifModifiedSince]) { response.writeHead(304, "Not Modified"); response.end(); } else { var raw = fs.createReadStream(realPath); var acceptEncoding = request.headers['accept-encoding'] || ""; var matched = ext.match(config.Compress.match); if (matched && acceptEncoding.match(/\bgzip\b/)) { response.writeHead(200, "Ok", {'Content-Encoding': 'gzip'}); raw.pipe(zlib.createGzip()).pipe(response); } else if (matched && acceptEncoding.match(/\bdeflate\b/)) { response.writeHead(200, "Ok", {'Content-Encoding': 'deflate'}); raw.pipe(zlib.createDeflate()).pipe(response); } else { response.writeHead(200, "Ok"); raw.pipe(response); } } } } }); }; pathHandle(realPath); }); server.listen(PORT); console.log("Server runing at port: " + PORT + ".");
Medan Tamat Tempoh mengisytiharkan masa apabila halaman web atau alamat URL tidak lagi dicache oleh penyemak imbas Setelah masa ini melebihi, penyemak imbas harus menghubungi pelayan asal. Masa tamat tempoh ditetapkan di sini kepada 1 tahun.
exports.Expires = { fileMatch: /^(gif|png|jpg|js|css)$/ig, maxAge: 60*60*24*365 }; exports.Compress = { match: /css|js|html/ig }; exports.Welcome = { file: "index.html" };
Enumerate jenis pelbagai sumber dan tetapkan Content-Type mengikut sambungan.
exports.types = { "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" };