Support Features:
Reading static files
Access to the directory can automatically look for the following index.html file, if not index.html lists the file list
MIME type support
Cache Support/Control
Supports gzip compression
Range support, breakpoint continuation
Global command execution
Child process Run
This article mainly and you introduced the actual combat node static file Server example, I hope to help everyone.
1. Create a service to read static files
First introduce the HTTP module, create a server, and listen to the configuration port:
Const HTTP = require (' http '); Const SERVER = Http.createserver (); Listener Request Server.on (' request ', Request.bind (this)); Server.listen (Config.port, () = { Console.log (' Static file service started successfully, Access Localhost:${config.port} ');
Write an FN to handle the request, return the static file, the URL module gets the path:
Const URL = require (' URL '); Const FS = require (' FS '); function request (req, res) {const {Pathname} = Url.parse (Req.url);//access path Const filepath = path.join (Config.root, pathname); File path fs.createreadstream (filepath). pipe (res);//Read file and respond}
Support to find index.html:
if (pathname = = =/') { const RootPath = path.join (config.root, ' index.html '); try{ Const INDEXSTAT = Fs.statsync (rootpath); if (indexstat) { filepath = RootPath; }} catch (e) { }}
When accessing the directory, list the file directories:
Fs.stat (filepath, (err, stats) = {if (err) { res.end (' not found '); Return } if (Stats.isdirectory ()) {let files = Fs.readdirsync (filepath); Files = Files.map (File = = ({ name:file, url:path.join (pathname, file) }); Let HTML = this.list () ({ title:pathname, files }); Res.setheader (' Content-type ', ' text/html '); Res.end (HTML); } }
HTML templates:
Function List () {let Tmpl = Fs.readfilesync (Path.resolve (__dirname, ' template ', ' list.html '), ' UTF8 '); Return Handlebars.compile (Tmpl); }
<! DOCTYPE html>
2.MIME Type Support
Use the MIME module to get the file type and set the encoding:
Res.setheader (' Content-type ', Mime.gettype (filepath) + '; Charset=utf-8 ');
3. Cache support
HTTP protocol cache:
cache-control:http1.1 content that tells the client how to cache data, as well as rules
Private Clients can cache
Public client and proxy server can be cached
MAX-AGE=60 cache content will expire in 60 seconds
No-cache needs to validate data using contrast cache, forcing re-authentication to the source server
No-store All content is not cached, forcing cache and contrast cache are not triggered
expires:http1.0 content, Cache-control will overwrite, tell the client when the cache expires
ETag: Hash value of content the next time a client request adds a If-none-match:etag value in the request header
Last-modified: Last modification time the next client request adds a If-modified-since:last-modified value to the request
Handlecache (req, res, stats, hash) {//When the resource expires, the client discovers the last request resource, the server has a send last-modified, and then requests it again with If-modified-since Const IFMODI fiedsince = req.headers[' if-modified-since ']; The server sends the ETag, and the client requests it again with the If-none-match field to ask if it expires const Ifnonematch = req.headers[' If-none-match ']; http1.1 content max-age=30 for forced cache for 30 seconds and 30 seconds to request again in cache private client-side cache only, proxy server is not cacheable res.setheader (' Cache-control ', ' private,max-age =30 '); http1.0 content is consistent with Cache-control tell the client what time, resource expiration priority is lower than Cache-control res.setheader (' Expires ', New Date (Date.now () + 30 * 100 0). toGMTString ()); Sets the hash res.setheader (' etag ', hash) generated by the ETag based on the content; Set last-modified file Last modified time const LASTMODIFIED = stats.ctime.toGMTString (); Res.setheader (' last-modified ', lastmodified); Determine if the etag expires if (ifnonematch && ifnonematch! = hash) {return false;}//Determine the last modified time of the file if (ifmodifiedsince &&A mp Ifmodifiedsince! = lastmodified) {return false;}//If present and equal, go cache 304 if (Ifnonematch | | ifmodifiedsince) {Res.writehead (304); Res.end (); return true; } else {returnFalse } }
4. Compression
The client sends the content, through the request head Accept-encoding:gzip, deflate tells the server to support which compression format, the server compresses the content according to the supported compression format. If the server is not supported, it is not compressed.
GetEncoding (req, res) { Const acceptencoding = req.headers[' accept-encoding ']; Gzip and deflate Compression if (/\bgzip\b/.test (acceptencoding)) { res.setheader (' content-encoding ', ' gzip '); return Zlib.creategzip (); } else if (/\bdeflate\b/.test (acceptencoding)) { res.setheader (' content-encoding ', ' deflate '); return Zlib.createdeflate (); } else { return null;} }
5. Continuation of the breakpoint
The server range:bytes=0-xxx in the request header to determine whether to do a range request, if the value exists and is valid, only send back the requested portion of the file content, the response status code becomes 206, indicating partial Content, and set the Content-range. If not, returns a 416 status code indicating that the request Range is not satisfiable. If you do not include a request header for range, you continue to respond in a regular manner.
GetStream (req, res, filepath, statobj) {let start = 0; Let end = Statobj.size-1; Const RANGE = req.headers[' range ']; if (range) { res.setheader (' accept-range ', ' bytes '); Res.statuscode = 206;//Returns the entire contents of a block let result = Range.match (/bytes= (\d*)-(\d*)/); if (result) { start = IsNaN (Result[1])? Start:parseint (Result[1]); End = IsNaN (Result[2])? End:parseint (Result[2])-1; } } Return Fs.createreadstream (filepath, { start, end });}
6. Global command execution
With NPM link implementation
Create a soft link for the NPM package catalog and chain it to {prefix}/lib/node_modules/
Create a soft link to the executable (bin) and chain it to {prefix}/bin/{name}
The NPM link command implements the global executable of the NPM Package command via the linked directory and executable file.
Package.json inside Configuration
{bin: {"hope-server": "Bin/hope"}}
Create a bin directory hope file below the project, using Yargs to configure command-line arguments
Tell the computer to run my files with node #! /USR/BIN/ENV node const YARGS = require (' Yargs '); const INIT = require ('.. /src/index.js '); Const ARGV = yargs.option (' d ', {alias: ' Root ', demand: ' false ', type: ' String ', DEFAULT:PROCESS.CWD (), Description: ' Static text The root directory '}). Option (' O ', {alias: ' Host ', demand: ' false ', default: ' localhost ', type: ' String ', Description: ' Configure listening host '}). opt Ion (' P ', {alias: ' Port ', demand: ' false ', type: ' Number ', default:8080, Description: ' Configure Port Number '}). Option (' C ', {alias: ' ch Ild ', demand: ' false ', type: ' Boolean ', Default:false, Description: ' Whether the child process is running '} '. Usage (' hope-server [Options] '). Example (' hope-server-d/-P 9090-o localhost ', ' listening for client requests on the 9090 port on this machine '). Help (' H '). argv; Start Service init (argv);
7. Child process Run
Implemented through Spawn
Index.js
const {Spawn} = require (' child_process '); Const SERVER = require ('./hope '); function init (argv) { //if configured as a child process to turn on the service if (argv.child) { ///Sub-process Start service Const child = spawn (' node ', [' Hope.js ', Json.stringify (argv)], { CWD: __dirname, detached:true, stdio: ' Inherit ' }); Background run child.unref (); Exit the main thread and let the child threads run process.exit (0) separately; } else { const SERVER = new server (argv); Server.start (); } } module.exports = Init;hope.js if (process.argv[2] && process.argv[2].startswith (' {')) {const ARGV = JSON. Parse (process.argv[2]); Const SERVER = new Hope (argv); Server.start (); }
8. Source code and testing
Source Address: Hope-server
NPM Install Hope-server-g
Go to any directory
Hope-server