1. The HTTP server is introduced

Sometimes the web address bar needs to use HTTP protocol, this time can be through the HTTP-server plug-in to achieve the effect. To install http-server globally, enter NPM i-g http-server.

npm i -g http-server
Copy the code

After installation, type in the directory of the file you want to openhttp-serverYou can turn it onhttpAgreement.

Let’s say I open a command line in a project directory



Enter http-server to start the service



And then open this uphttp://127.0.0.1:8081/You can see this effect, the current folder directory deconstruct and files.



This is the simplest usage scenario, and it can be configured with many options. For example, http-server –port 3000 can be used to set the port number of the service. You can also use –directory to specify the directory.Github.com/http-party/…

2. Code implementation

1. Requirements analysis and implementation

  • inpackage.jsonIn the configurationbinField, and then usenpm linkConnect to globalnpmPackage, so you can use your own commands globally, you can use the chalk toolchalkSets the file color for the prompt
  • The introduction ofcommanderThe package takes the parameters entered by the user on the command line to override the default parameters, set command line prompts, colors, and so on.
  • withhttp-serverCreate a service that reads the directory according to the requested path and determines whether it is a file or folder. If it is a file, return the corresponding file, otherwise return a current directory structurehtml. The returnedhtmlYou can useejsThis package is generated from a template, and different types of files require different response headersContent-TypeType, can be usedmimeThe package resolves.

2. Code implementation

1. Initialize the project

npm init -y
Copy the code

Then change the project name to my-http-server, configure the bin field in package.json, add a bin folder to create WWW and config.js files, the bin directory is the tool startup directory, and execute the my-hs command to directly execute the code in WWW. Create a SRC directory and add a server.js file to handle the client’s request and response logic. Create template. HTML to handle the HTML case where the directory is a directory to return to. Then install chalk, Commander, EJS, and MIME.

The directory structure is as follows:

| - bin | | - config. Js -- -- -- -- -- -- -- -- -- -- -- -- - the default configuration services | | - WWW -- -- -- -- -- -- -- -- -- -- -- -- -- service startup file | | - SRC | | - server. Js -- -- -- -- -- -- -- -- - | service logic processing | - template. HTML -- -- -- -- -- -- -- -- -- -- the HTML template, is used to render folder directory structure | | - package. JsonCopy the code

package.json

{
  "name": "my-hs"."version": "1.0.0"."description": ""."bin": {
    "my-hs": "./bin/www"
  },
  "main": "index.js"."scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": []."author": ""."license": "ISC"."dependencies": {
    "chalk": "^ 4.1.0." "."commander": "^ 6.2.1." "."ejs": "^ 3.1.5." "."mime": "^ 2.4.7." "}}Copy the code

Config.js default configuration file

// Customize the commands to be displayed on the command line
const config = { // Set the parameters for yourself
    'port': {option:'-p,--port <n>'.// 
      
        represents a value
      
        descriptor:'set your server port'.default: 8080.usage:'my-hs --port <n>'
    },
    'directory': {option:'-d,--directory <n>'.descriptor:'set your server start directory'.default: process.cwd(),
        usage: 'my-hs --directory <n>'
    },
    'cache': {option:'-c,--cache <n>'.descriptor:'set your server cache'.default:'no-cache'.usage: 'my-hs --cache <n>'}}module.exports = config;
Copy the code

WWW file note: the #! /usr/bin/env node is a fixed form that tells the system to execute the file using node,

#! /usr/bin/env node
const program = require('commander');
const chalk = require('chalk');
const config = require('./config');
const Server = require('.. /src/server')

 // The name used for the configuration
program.name('my-hs');

// The default configuration object
const defaultConfig = {};

// Use the sample collection
const usageList = [];

// Go through the configuration to the current program
Object.entries(config).forEach(([key, value]) = > {
    defaultConfig[key] = value.default;
    usageList.push(value.usage)
    program.option(value.option, value.descriptor);
});

// Listen for the --help event to display the sample on the command line
program.on('--help'.function () {
    console.log('Examples:');
    usageList.forEach(line= >{
        console.log(`  ${chalk.green(line)} \r`); })})// Parse the user's execution parameters
program.parse(process.argv); 

// Make a configuration based on the user's parameters and default values
function mergeOtions(defaultConfig,newConfig){
    const options = {}
    for(let key in defaultConfig){
        if(! (keyin newConfig)){
            options[key] = defaultConfig[key]
        }else{
            // Verify that newConfig meets my expectations
            options[key] = newConfig[key]
        }
    }
    return options
}
let options = mergeOtions(defaultConfig,program);

// Get the user's parameters to create a service and start it
let server = new Server(options);
server.start();
Copy the code

Server. The js file

const http = require('http');
const url = require('url'); // Parse url parameters
const path = require('path');
const fs = require('fs').promises; // Get the FS module's Promise method
const { createReadStream, createWriteStream } = require('fs'); // Get the read/write stream method
const chalk = require('chalk'); // Chalk tool
const mime = require('mime'); // Parses the file mime type package
const ejs = require('ejs'); // Generate the HTML package

/ / service class
class Server {
    constructor(options) {
        this.port = options.port;
        this.directory = options.directory;
        this.cache = options.cache;
    }
    async handleRequest(req, res) {
        let { pathname } = url.parse(req.url);
        pathname = decodeURIComponent(pathname); // Set base64 to Chinese
        // List all folders
        let requestUrl = path.join(this.directory, pathname); // Resolve will return to the root path
        try {
            const statObj = await fs.stat(requestUrl); // Read the path of the corresponding type, directory or file
          	// If it is a directory, return an HTML for that directory
            if (statObj.isDirectory()) {
              	// Get all files and folders in this directory
                let dirs = await fs.readdir(requestUrl);
                let content = await ejs.renderFile(path.resolve(__dirname, 'template.html'), {
                    dirs: dirs.map(dir= > ({
                        name: dir,
                        pathname: path.join(pathname, dir) // Prefix to get the deep folder structure}}))); res.setHeader('Content-Type'.'text/html; charset=utf-8');
                res.end(content);
            } else {
                // file reads files
                this.sendFile(requestUrl, req, res, statObj)
            }
        } catch (e) {
            console.log(e)
            this.sendError(e, req, res); }}// Error response
    sendError(err, req, res) {
        res.statusCode = 404;
        res.end('Not Found')}// Set the response header based on the file type and return the file
    sendFile(filePath, req, res, stat) {    
        res.setHeader('Content-Type'.`${mime.getType(filePath)}; charset=utf-8`)
        createReadStream(filePath).pipe(res); 
    }
  	// Start the service method
    start() {
        const server = http.createServer(this.handleRequest.bind(this));
        server.listen(this.port, () = > {
            console.log(`${chalk.yellow('Starting up http-server, serving')}`);
            console.log(`  http://127.0.0.1:${chalk.green(this.port)}`)}); }}module.exports = Server;
Copy the code

File directory HTML template

<! DOCTYPEhtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <title>Document</title>
</head>
<body>
    <%dirs.forEach(dir=>{%>
        <li><a href="<%=dir.pathname%>"><%=dir.name%></a></li>The < %}) % ></body>
</html>
Copy the code

Use 3.

Enter in the command toolmy-hs --helpWe’re listening in the code--helpEvent showing the use sample.



Enter in the command toolmy-hs -d /Users/xujian/workPlace/vue-better-drawerIn/Users/xujian/workPlace/vue – better – the drawer launched an HTTP service directory



Browser openhttp://127.0.0.1:8080/This address gives access to the file structure in this directory



Can display specific file file class capacity:





And access to deeper directories:



An easy versionhttp-serverGithub address:Github.com/Itherma/my-…