Dark horse node JS start

Node.js start

  • Node.js is a server language

  • The language of the server is different from that of the front-end. The front-end only has H5,CSS,JS and other languages based on it, but there are many languages on the server that can realize the most basic functions such as H5. They are parallel and independent, such as Java, PHP, python, ruby Net,Nodejs

  • Use node The reason for JS is that you can use js language, which is friendly to the front end

  • Node. What is JS

    1. It is a JS runtime environment (Runtime lib), not a library, not a framework, not a language. (it can be understood that it is the same as a browser, but a little different)

      • What is JS in browser

        • Basic syntax ECMAScript
        • DOM
        • BOM
      • Node. What is JS in JS

        • No BOM, DOM (because the server does not process pages)
        • Basic syntax ECMAScript
        • Server level API (file reading and writing, network service construction, http service...)
    2. It is an event driven, non blocking IO model (asynchronous), efficient and lightweight

    3. The npm ecosystem is also the largest open source ecosystem

    4. It is built on the v8 engine

  • What can Nodejs do

    • Web background
    • Command line tools (for example: hexo, gulp...)
    • Interface server

Simple program

Just create a js file directly and write it without relying on html files. Then use node XX js execution file

Write hello world

var foo='hello world'
console.log(foo);

Then try to read and write files on the server. Note that the HTML of the browser does not support file reading and writing

// fs is the abbreviation of file system, which means file system 
// If you want to use the file io in the Node, you must introduce the fs module
// fs module provides relevant APIs for all text operations
var fs=require("fs");

// readFile is used to read files. The first one is the address and the second one is the callback function. The callback accepts two parameters, error and data
//    -Error indicates whether there is an error in reading the file. If there is an error, it is the error object. Yes, it is null
//    -Data is the read data. If there is an error, it is null. Yes, it is a hexadecimal result. You need toString to see it
fs.readFile("./test",function(error,data){
    if(!error)
        console.log(data.toString());
    else
        console.log("ERROR!!\n"+error)
});

// The tst file does not exist
fs.readFile("./tst",function(error,data){
    if(!error)
        console.log(data.toString());
    else
        console.log("ERROR!!\n"+error)
});

// The parameter is the path content callback function (accept error)
fs.writeFile("./out","Test text",function(error){
    if(error)
        console.log("File write failed");
})

// The file name has illegal characters. Writing failed
fs.writeFile("./o/*-ut","Test text",function(error){
    if(error)
        console.log("File write failed"+error);
})

The simplest http service

Core module http required

// Load http core module
var http = require('http');

// Use HTTP Create server create a web server
// Return a server instance
var server = http.createServer();

// Sending request receiving request processing request

// Register the request time, and the callback function will be executed after receiving the request
server.on("request",function(){
    console.log("Received client request");
})

// Bind 3000 port and start the server
server.listen(3000,function(){
    console.log("The server started successfully");
});

Response request

var http = require('http');

var server = http.createServer();

//The callback function of request accepts two functions
//    -Request object
//      Get the request information of the client, such as the path
//    -Reponse corresponding object
//      The response object can be used to send corresponding messages to the client

server.on("request",function(request,response){
    // The address of the output access path 127.0.0.1:3000/a is / a
    console.log("Received client request, The request path is"+request.url);
    // response.write can be used to send the corresponding message
    // write can be used multiple times, but it must be ended with end, otherwise the client will always accept it and cannot send requests after end
    response.write("hello");
    response.write("123456");
    response.end();
})

server.listen(3000,function(){
    console.log("The server started successfully");
});

p.s. the browser will have a default request favicon when accessing No need to get icon, ICO

Different paths and different requests

var http = require('http');

var server = http.createServer();

server.on("request",function(request,response){
    var value=""
    var obj=[{
        title:123,
        name:456,
    },{
        title:45,
        name:45,
    },{
        title:23,
        name:4,
    }];
    switch (request.url) {
        case "/":value="index";break;
        case "/log":value="land";break;
        case "/reg":value="register";break;
        default:value="error";break;
    }
    response.write("Upon request, enter"+value+"page");
    // Note that the corresponding contents can only be binary files or strings. JSON objects and arrays are not supported
    response.write(JSON.stringify(obj));
    response.end();
})

server.listen(3000,function(){
    console.log("The server started successfully");
});

Get server port and client port number

server.on("request",function(request,response){
    console.log("Service port:"+request.socket.localPort+"Client port"+request.socket.remotePort);
}

The problem of Chinese garbled code

The node server sends utf8 data by default, but the browser doesn't know, so it parses according to the default code of the operating system. Therefore, the server needs to tell the browser that utf8 is used. The method is

rep.setHeader('Content-Type',"text/plain;charset=utf-8")

js in Node

  • ECMAScript
    • No DOM,BOM
  • Core module
    • Node provides JS with server level API s, which are packaged into a named core module, such as fs file system, httphttp module, path module and os operating system module
    • Later, when it is said that it is a core module, it is directly named var XXX=require("YY")XX. It is not mandatory, and it is better to be the same as YY
  • Third party module
  • Custom module

Simple modularization

Two methods: require is used to load and export is used to export
require is a method
Its function is to load modules
There are three types of modules
-Named core modules, such as fs, http
-The file module written by the user (when require d. / cannot be omitted, otherwise it will become the core module, and. JS can not be written)

1.js

console.log("Start execution 1");
var mod2=require("./2.js")
console.log("End execution 1");

2.js

console.log("The external file is loaded")
  • In node, there is no global scope, only module scope, that is, variables can only be used inside this file
  • After require, the internal code will be executed automatically, and then the interface object of the file will be obtained
  • If you want to not only execute the sub module code, but also use the content in the interface object, you need to
    1. Instantiate the method to an object in the cost module
    2. Export the objects to be exposed as interface objects

1.js continued

console.log(mod2.foo)
console.log(mod2.plus(1,1.2));

2.js continued

exports.foo="hello";
exports.plus=function(a,b){
    return a+b;
}

Response content type

rep.setHeader("Content-Type","text/plain;charset=utf-8");

Notice where the double quotation marks lead

Settings for and HTML code

The above is for plain text. Try the following settings

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>chinese<a href="javascript:;">test</a></p>");
    rep.end();
})
server.listen(3000,function(){
    console.log("node start...");
})
  • It is found that 123456 is displayed normally with no label. You can see that the package received by the network has a label. The browser renders the package, which makes the user unable to see the label
  • Chinese display failed because utf-8 is not set

Try setting

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
    rep.setHeader("Content-Type","text/plain;charset=utf-8");
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>chinese<a href="javascript:;">test</a></p>");
    rep.end();
})
server.listen(3000,function(){
    console.log("node start...");
})

It is found that the Chinese display is normal, but the label is displayed. This is because node clearly tells the browser that this is text and does not allow the browser to parse. The solution is to change plain to html

var http=require("http");
var server=http.createServer();
server.on("request",function(req,rep){
    rep.setHeader("Content-Type","text/html;charset=utf-8");
    rep.write("<p>123<a href="javascript:;">456</a></p>");
    rep.write("<p>chinese<a href="javascript:;">test</a></p>");
    rep.end();
})
server.listen(3000,function(){
    console.log("node start...");
})

Chinese and labels are displayed normally

Note that the content type can only be set once for each response sent, and cannot be written again after each end

Other types of content type

  • html file
var http=require("http");
var fs=require("fs");
const { report } = require("process");
var server=http.createServer();

server.on("request",function(req,rop){
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
        if(error)
            rop.write("ERROR");
        else
            rop.write(data);
    });
    rop.write("123");
    rop.end();
})

server.listen(3000,function(){
    console.log("working...");
})

Note that if there is a problem, you can only see 123. Because the callback function is an asynchronous module, when you read the callback function, you will put it into the event queue and wait to execute the main thread, so you read the ROP write("123"); Then there's ROP End wait until the main code ends, then open the time queue loop and send the request, but it's late, it's already end!!!, How to verify?? Replace with the following code and wait until you read setTimeout(rop.end,10000); Start thread timing, read the event queue, and then send end 10 seconds later. The source file is displayed. At the same time, you can see that there is 123 first and then HTML code!!

server.on("request",function(req,rop){ 
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
        if(error)
            rop.write("ERROR");
        else
            rop.write(data);
    });
    rop.write("123");
    setTimeout(rop.end,10000);
})

So the best way is

var http=require("http");
var fs=require("fs");
const { report } = require("process");
var server=http.createServer();

server.on("request",function(req,rop){
    rop.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readFile("./index.html",function(error,data){
        if(error)
            rop.end("ERROR");
        else
            rop.end(data);
    });
})

server.listen(3000,function(){
    console.log("working...");
})

The termination must be in the asynchronous module

  • png
// png pictures do not need to specify the code. Generally, only character data specifies the code
rop.setHeader("Content-Type","image/png");
    fs.readFile("./3.png",function(error,data){
        if(error)
            rop.end("ERROR");
        else
            rop.end(data);
        
    });
  • Other types of content type
    • Media format
      • text/html: HTML format
      • text/plain: plain text format
      • text/xml: XML format
      • image/gif: gif picture format
      • image/jpeg: jpg image format
      • image/png: png picture format
    • Media type starting with application:
      • application/xhtml+xml: XHTML format
      • application/xml: XML data format
      • application/atom+xml: Atom XML aggregation format
      • application/json: JSON data format
      • application/pdf: pdf format
      • application/msword: Word document format
      • Application / octet stream: binary stream data (such as common file download)
      • application/x-www-form-urlencoded: the default encType in < form encType = ">. The form data is encoded as key/value format and sent to the server (the default format of the form submission data)
    • More( https://tool.oschina.net/commons)[https://tool.oschina.net/commons ]

Implement some Apache functions

Realize directory browsing function

  • Enter the address to access some files
var http=require("http");
var fs=require("fs");
var server=http.createServer();

server.on("request",function(req,res){
    rep.setHeader("Content-Type","text/plain;charset=utf-8")
    var reg=new RegExp("^\/file\/","i");
    if(reg.test(req.url)){
        fs.readFile(req.url.replace(reg,".\/"),function(error,data){
            if(error){
                res.end("ERROR REQ");
                console.log(error);
            }else{
                res.end(data);
            }
        });
    }else{
        res.end("welcom");
    }
});

server.listen(3000,function(){ 
    console.log("working...");
})

Enter the web address to access the file directory

Requirement 1 displays the file directory under the specified folder
If you need to use the file directory, it must be the fs module. Check the API to get fs Readdir ("path", function (error, files)) files is an array of file names (note that neither d is capitalized)

var fs=require("fs");

fs.readdir("../01/",function(error,files){
    if(error)
        console.log(error);
    else
        console.log(files);
});

Dynamic demand display 2
Of course, we can replace the violent implementation with a string

<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
    <meta charset="utf-8">
    <style>
        h1 {
            border-bottom: 1px solid #c0c0c0;
            margin-bottom: 10px;
            padding-bottom: 10px;
            white-space: nowrap;
        }
        table {
            border-collapse: collapse;
        }
        th {
            cursor: pointer;
        }
        td.detailsColumn {
            -webkit-padding-start: 2em;
            text-align: end;
            white-space: nowrap;
        }
        a.icon {
            -webkit-padding-start: 1.5em;
            text-decoration: none;
            user-select: auto;
        }
        a.icon:hover {
            text-decoration: underline;
        }
        a.file {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABnRSTlMAAAAAAABupgeRAAABHUlEQVR42o2RMW7DIBiF3498iHRJD5JKHurL+CRVBp+i2T16tTynF2gO0KSb5ZrBBl4HHDBuK/WXACH4eO9/CAAAbdvijzLGNE1TVZXfZuHg6XCAQESAZXbOKaXO57eiKG6ft9PrKQIkCQqFoIiQFBGlFIB5nvM8t9aOX2Nd18oDzjnPgCDpn/BH4zh2XZdlWVmWiUK4IgCBoFMUz9eP6zRN75cLgEQhcmTQIbl72O0f9865qLAAsURAAgKBJKEtgLXWvyjLuFsThCSstb8rBCaAQhDYWgIZ7myM+TUBjDHrHlZcbMYYk34cN0YSLcgS+wL0fe9TXDMbY33fR2AYBvyQ8L0Gk8MwREBrTfKe4TpTzwhArXWi8HI84h/1DfwI5mhxJamFAAAAAElFTkSuQmCC ") left top no-repeat;
        }
        a.dir {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAd5JREFUeNqMU79rFUEQ/vbuodFEEkzAImBpkUabFP4ldpaJhZXYm/RiZWsv/hkWFglBUyTIgyAIIfgIRjHv3r39MePM7N3LcbxAFvZ2b2bn22/mm3XMjF+HL3YW7q28YSIw8mBKoBihhhgCsoORot9d3/ywg3YowMXwNde/PzGnk2vn6PitrT+/PGeNaecg4+qNY3D43vy16A5wDDd4Aqg/ngmrjl/GoN0U5V1QquHQG3q+TPDVhVwyBffcmQGJmSVfyZk7R3SngI4JKfwDJ2+05zIg8gbiereTZRHhJ5KCMOwDFLjhoBTn2g0ghagfKeIYJDPFyibJVBtTREwq60SpYvh5++PpwatHsxSm9QRLSQpEVSd7/TYJUb49TX7gztpjjEffnoVw66+Ytovs14Yp7HaKmUXeX9rKUoMoLNW3srqI5fWn8JejrVkK0QcrkFLOgS39yoKUQe292WJ1guUHG8K2o8K00oO1BTvXoW4yasclUTgZYJY9aFNfAThX5CZRmczAV52oAPoupHhWRIUUAOoyUIlYVaAa/VbLbyiZUiyFbjQFNwiZQSGl4IDy9sO5Wrty0QLKhdZPxmgGcDo8ejn+c/6eiK9poz15Kw7Dr/vN/z6W7q++091/AQYA5mZ8GYJ9K0AAAAAASUVORK5CYII= ") left top no-repeat;
        }
        a.up {
            background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNpsU0toU0EUPfPysx/tTxuDH9SCWhUDooIbd7oRUUTMouqi2iIoCO6lceHWhegy4EJFinWjrlQUpVm0IIoFpVDEIthm0dpikpf3ZuZ6Z94nrXhhMjM3c8895977BBHB2PznK8WPtDgyWH5q77cPH8PpdXuhpQT4ifR9u5sfJb1bmw6VivahATDrxcRZ2njfoaMv+2j7mLDn93MPiNRMvGbL18L9IpF8h9/TN+EYkMffSiOXJ5+hkD+PdqcLpICWHOHc2CC+LEyA/K+cKQMnlQHJX8wqYG3MAJy88Wa4OLDvEqAEOpJd0LxHIMdHBziowSwVlF8D6QaicK01krw/JynwcKoEwZczewroTvZirlKJs5CqQ5CG8pb57FnJUA0LYCXMX5fibd+p8LWDDemcPZbzQyjvH+Ki1TlIciElA7ghwLKV4kRZstt2sANWRjYTAGzuP2hXZFpJ/GsxgGJ0ox1aoFWsDXyyxqCs26+ydmagFN/rRjymJ1898bzGzmQE0HCZpmk5A0RFIv8Pn0WYPsiu6t/Rsj6PauVTwffTSzGAGZhUG2F06hEc9ibS7OPMNp6ErYFlKavo7MkhmTqCxZ/jwzGA9Hx82H2BZSw1NTN9Gx8ycHkajU/7M+jInsDC7DiaEmo1bNl1AMr9ASFgqVu9MCTIzoGUimXVAnnaN0PdBBDCCYbEtMk6wkpQwIG0sn0PQIUF4GsTwLSIFKNqF6DVrQq+IWVrQDxAYQC/1SsYOI4pOxKZrfifiUSbDUisif7XlpGIPufXd/uvdvZm760M0no1FZcnrzUdjw7au3vu/BVgAFLXeuTxhTXVAAAAAElFTkSuQmCC ") left top no-repeat;
        }
        html[dir=rtl] a {
            background-position-x: right;
        }
        #parentDirLinkBox {
            margin-bottom: 10px;
            padding-bottom: 10px;
        }
        #listingParsingErrorBox {
            border: 1px solid black;
            background: #fae691;
            padding: 10px;
            display: none;
        }
    </style>
    <title id="title">/home/liukairui/CODE/ Index of</title>
</head>

<body>
    <div id="listingParsingErrorBox">too bad! Google Chrome The data sent by the server cannot be interpreted. please<a
            href="http://code. google. COM / P / chromium / issues / entry "> report errors < / a > and attach the < a href =" location "> original list < / a >. < / div >
    <h1 id="header">/home/liukairui/CODE/ Index of</h1>
    <div id="parentDirLinkBox" style="display: block;">
        <a id="parentDirLink" class="icon up" href="/home/liukairui/CODE/..">
            <span id="parentDirText">[Parent directory]</span>
        </a>
    </div>
    <table>
        <thead>
            <tr class="header" id="theader">
                <th id="nameColumnHeader" tabindex="0" role="button">name</th>
                <th id="sizeColumnHeader" class="detailsColumn" tabindex="0" role="button">
                    size
                </th>
                <th id="dateColumnHeader" class="detailsColumn" tabindex="0" role="button">
                    modification date
                </th>
            </tr>
        </thead>
        <tbody id="tbody">
            {{HERETOREPLACE}}
        </tbody>
    </table>
</body>
</html>
var fs=require("fs");
var http=require("http");

var server=http.createServer();
server.on("request",function(req,res){
    var content="";
    res.setHeader("Content-Type","text/html;charset=utf-8")
    fs.readdir("./",function(error,files){
        if(error){
            res.end("404 Not Find");
            return;
        }else{
            files.forEach(function(FILENAME){
                content+=`<tr><td data-value="${FILENAME}/"><a class="icon dir" href="/home/liukairui/CODE/${FILENAME}/">${FILENAME}/</a></td><td class="detailsColumn" data-value="0"></td><td class="detailsColumn" data-value="1602264292">2020/10/10 1 am:24:52</td></tr>`
            })
        }
    });
    fs.readFile("./index.html",function(error,file){
        if(error)   
            res.end("404 Not Find");
        else{
            // Use string substitution to implement
            res.end(file.toString().replace("{{HERETOREPLACE}}",content));
        }
    });
});

server.listen(3000,function(){
    console.log("working...");
})

For the HTML code to be inserted, the content to be spliced can be wrapped in ` ` backquotes, so as to generate the template string. The feature is to retain the original output such as space and carriage return, so as to replace the specified content. The method is

var arry=["BOB","KARRY"];
arry.forEach(function(username){
    console.log(`123${username}123`);
})

The template cannot be defined in advance, otherwise an error is reported and the variable cannot be found

For more complex web pages, you need a template engine (similar to an angular template). Use art template here
The principle of this kind of template is relatively simple. It is to find specific variables in a given board and then replace them. It supports circular construction operations such as * ng for
There are two forms of common template engines: rendering on the client side and rendering on the server side

  • Render on client
    Write the content to be replaced in < script text / template > < / script >, and write the replacement variable in script. See Chinese translation documents

  • Rendering on the server
    Select npm to install in the corresponding directory

    npm install art-template --save
    

    Variables in HTML files are enclosed with {{variable}}
    The value of {$array} in {$array} is the same as the value of {$array} in {$array} in {each} loop
    ...
    Get the HTML file and replace it with the render command

    var template=require("art-template");
    
    fs.readFile("./XXX.html",function(error,data){
        if(error){
            res.end("404");
            return;
        }
        var htmls = template.render(data.toString(),{
            // datas JSON Obj
        });
        res.end(htmls);
    });
    

In this project, we need to obtain directory information, so we choose server-side rendering

  • Differences between server-side rendering and client-side rendering
    • Server rendering
      • It is to obtain the template file through the server, then complete the page replacement at the server, and directly send the finished HTML code to the client
      • The server can get all the files by making a request only once
      • ctrl+u view the web page source code / F12 can be seen directly
    • Client rendering
      • The server sends the template file to the client, the client browser finds that there are variables that have not been replaced, sends the required variable request to the server, the server returns the variable value, and the client renders the result
      • The server needs to send at least two requests (template + variable) to render the page
      • ctrl+u cannot see the content, and F12 can see the element
    • Advantages and disadvantages
      • The content that the server needs to send is one-time, and the volume is large, so the speed is slow, and the number of times the client is small, so the speed is fast
      • In the project, we generally adopt the rendering method of combining the client and the server. This is because SEO can only climb to the web page rendered by the server and can't send AJAX, so we can't get the client rendering page. The loading of client rendering is fast, so we need to combine the two. If you don't need SEO, you also want to use the client with good user experience, and you need the service port of SEO

Realize the function of message board

  • When actually building a web page, we'd better separate the files used for services from HTML, CSS and JS of the web page. Generally, we do the following blocks
    • ./app.js server file
    • . / views to place HTML files
    • . / public places files that may be accessed by the browser. css,js,img,lib... Folders store css,js,img and third-party files (such as jQuery and bootstrap)

The purpose of this is to set permissions so that the browser can access some files. For example, in a request, the browser directly returns the original HTML, and the browser finds it necessary to link style when parsing css, then the browser will send a request to the server again. At this time, the server should be able to return the css file, but it can't be said that the browser will give whatever it wants to access, so put the files that may be requested by the browser (href,link in css,js,img,video... Tag) under a folder

Of course, it's too troublesome to judge files one by one. You can write it down in the last else of if (url = = '/') else if

var url=req.url;
var reg=new RegExp("^\/public\/","i");
else if(reg.test(url)){
    fs.readFile("."+url,function(error,data){
        if(error){
        res.end("404");
        return;
        }
        res.end(data);
    })
}

For judging whether it starts with / public /, it can also be written as req indexOf("/public/")===0
It is worth noting that when accessing, the url that the user accesses should be preceded by Otherwise, you can directly access the root directory
Then write 404 pages in the same way

if(error){
    fs.readFile("./views/404.html",function(err,dat){
        if(err)
        res.end("404 Not Find.")
        else
        res.end(dat);
    });
    return;
}

Also note that you should not write res.setheader ("content type", "text / HTML; charset = UTF-8"), otherwise the css will explode directly, so don't write it, and then the utf8 of HTML will disappear. Directly write < meta charset = "UTF-8" > in the HTML file, which is the same as the previous res.setheader ("content type", "text / HTML; charset = UTF-8"), but it is only effective for HTML and more convenient

Beautify url: now many websites are www.xxx COM / xxx / xxx / instead of www.xxx com/xxx/xxx/YYY. html, we can also realize this beautification function, which is very simple, that is, we disdain it in all html a tags html, and then change the judgment of node

Verification of form submission page

The minimum number of name verification is 2 and the maximum number is 10. Prompt information. Set name, otherwise it cannot be submitted

<input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="Please write your name">

The shortest content verification is 5 and the longest is 20. The prompt message is set to name, otherwise it cannot be submitted

<textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>

There are two types of form submission
-Default synchronous submission behavior
-Asynchronous commit

Parse the get request into an object: there is a URL module in node, which can use URL Parse (req. URL, true) returns a URL object, which contains pathname as the request address (no get information), and query is the object form of the request string

Redirect the successfully submitted page to the home page
-Setting the status code to 302 represents temporary redirection
-In the response header, tell the client to redirect there, and once it receives 302, it will initiate a new request

res.statusCode=302;
res.setHeader("Location","/");
res.end();

What is the difference between permanent redirection and temporary redirection
-Permanent 301 temporary 302
-The permanent redirection browser will remember after receiving it once, and then the access will not request direct jump
-Temporary redirection does not remember

finished product

html file

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="/public/css/bootstrap.css">
</head>

<body>
  <div class="header container">
    <div class="page-header">
      <h1><a href="/">home page</a> <small>Comment</small></h1>
    </div>
  </div>
  <div class="comments container">
    <!-- 
      How was the form submitted in the past?
      The form control element to be submitted in the form must have name attribute
      Form submission is divided into:
        1. Default commit behavior
        2. Form asynchronous submission

        action It is the address of the form submission. To put it bluntly, it is the address of the request url address
        method Request method
            get
            post
     -->
    <form action="/commit" method="get">
      <div class="form-group">
        <label for="input_name">Your name</label>
        <input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="Please write your name">
      </div>
      <div class="form-group" >
        <label for="textarea_message">Message content</label>
        <textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
      </div>
      <button type="submit" class="btn btn-default">publish</button>
    </form>
  </div>
</body>

</html>

js file

var http=require("http");
var fs=require("fs");
var template=require("art-template")
var urlM=require("url");
var server=http.createServer();
var comments=[
  {name:"LiuKairui",message:"Test1",dateTime:"20200101"}
]

server.on("request",function(req,res){
  var url=req.url;
  var reg=new RegExp("^\/public\/","i");
  if(url==='/'){
    fs.readFile("./views/index.html",function(error,data){
      if(error){
        fs.readFile("./views/404.html",function(err,dat){
          if(err)
            res.end("404 Not Find.")
          else
            res.end(dat);
        });
        return;
      }
      var htmls=template.render(data.toString(),{
        comments:comments
      });
      res.end(htmls);
    })
  }else if(url==="/post"){
    console.log("WORK POST");
    fs.readFile("./views/post.html",function(error,data){
      if(error){
        fs.readFile("./views/404.html",function(err,dat){
          if(err)
            res.end("404 Not Find.")
          else
            res.end(dat);
        });
        return;
      }
      res.end(data);
    })
  }else if(reg.test(url)){
    fs.readFile("."+url,function(error,data){
      if(error){
        fs.readFile("./views/404.html",function(err,dat){
          if(err)
            res.end("404 Not Find.")
          else
            res.end(dat);
        });
        return;
      }
      res.end(data);
    })
  }else if(urlM.parse(url,true).pathname=="/commit"){
    comments.push({name:urlM.parse(url,true).query.name,message:urlM.parse(url,true).query.message,dateTime:new Date().toDateString()})
    res.statusCode=302;
    res.setHeader("Location","/");
    res.end();  
  }else{
    fs.readFile("./views/404.html",function(err,dat){
      if(err)
        res.end("404 Not Find.")
      else
        res.end(dat);
    });
  }
});

server.listen(3000,function(){
  console.log("working...");
})

[miscellaneous] several methods of traversing element content

  1. JS native for
  2. ES5 starts traversing obj forEach(function(item[,index,array]){}) IE8+
  3. Method of jQuery function $ each(obj,function(i,item) note that this obj is an ordinary js array
  4. Method of jQuery instance $obj each(function(index,element))
  5. jQuery array can be converted into general js array by [] slice. The principle of call ($arry) is

slice method can be used to convert an array like object / collection into a new array. You just need to bind the method to this object. arguments in a function is an example of a class array object.

function list() {
  return Array.prototype.slice.call(arguments);
}

[] is inherited from Array, so [] slice and Array protptype. slice points to the same method

[].slice === Array.prototype.slice; // true

So we have a way to convert arrays
For traversable objects, you can use array From() to convert
For class arrays (with length attribute), you can use [] slice.call() or array prototype. Call() to convert

call( a r r ) mutually When to yes arr) is equivalent to arr) so arr is this in the function, and then this is cut into an array. The cutting function is array prototype. Clice() function, that is [] clice()
clice's function is to return the position of the first parameter of the array to the last when there is a parameter. The two are to traverse an array that is closed on the left and open on the right. If you don't write, it is from beginning to end

node's console

In the browser, we can use the console to conduct simple small tests, or in the node. Enter node under cmd and press enter to enter the node console. Different from python and browser, it can call directly when using the core module without requiring

Modular system

Writing applications in node is mainly about using

  • ECMAScript
  • Core module
  • Third party module
  • Custom module

The core modules are mainly

  • File system fs
  • HTTP service http
  • url path parsing url
  • Path processing path
  • Operating system os

Third party modules have

  • art-template
  • Download and use through npm

What is flower module

If a platform has

  • File scope
  • Communication rules
    • Load require
    • export
      It can be said that it is modular

CommonJS module specification

JS itself does not support modularization. JS in Node has a modular system

  • Module scope
  • Use require to load the module
  • Exporting modules using exports
    • Use exports XX = XX export XX variable or method
    • Exports exports the whole module. You need to use instances to accept the module and then use instances Gets the element using the method of the variable
    • If you only need a variable or method, you can write module in the module Exports = object, and then require gets the specific variable / method

Load require

Syntax:

var Custom instance=require("modular")

Function is

  • Execute all codes in the module
  • Assign the element in the module to be exported to the custom instance

Export exports

  • node is the scope of the module. All members in the default file are valid only in the current file module
  • For members who want to be accessed by other modules, you need to assign variables to exports
  • If you want to export multiple members
exports.XX=XX;
  • If you want to export a single member
module.exports=XX;

Don't write too much, or it will cover the previous one

principle
In node, each module has a module object and an exports object in this module. This object is empty by default. By default, node will write a return module at the end of the code Exports whoever require s this module will get the module Exports, we found that we need module every time we export exports. XXX = XXX is very troublesome. Node added a sentence in front of it and it's done

var exports=module.exports;

// The code you wrote

return module.exports;

One is module and the other is global. Note that module is not global
As a result, when you come up, you let exports=function directly modify the pointer of exports, and then the mounted ones are directly mounted to the function, which has nothing to do with the original module

If you really want to tangle, the syntax can be written as module export={obj1,obj2,obj3,obj4...}

Loading rules for require

Trial cases
A.js

require('./B');
require('./C');

B.js

console.log("B Loading succeeded");
require('./C');

C.js

console.log("C Loading succeeded");

Execute A.js and find that the result is

B Loading succeeded
C Loading succeeded

The reason is that A executes first and then enters B. after B outputs, it directly requires to enter C. C execution ends, B execution ends, and A executes the next line. It is found that C has been required, so it does not execute the code, but only obtains the interface object
This is the principle of require cache priority loading. It will not be loaded repeatedly, but only get the interface
We call the content in require() the module identifier

  • The. js suffix can be omitted
  • If the identifier does not have a path identifier, it will be considered as a core module / third-party module (so at least one. / module)
  • The essence of the core module is a file, but it has been binary compiled, so you can write the name directly
  • If the written identifier has no path and no module name, it is found/ node_modules / third-party module name, and then find package The module entry of main of JSON file. If the file or main cannot be found, it will automatically find indexd JS, if you still don't find it, go to the superior directory, and so on. If you still can't find it, an error will be reported, in which node can pass/ package-lock. The JSON file queries whether the package is already installed.
  • Ensure that a project has at most one node_modules / folder

To sum up, the loading order of node for a module is

  • Priority cache load
  • Core module loading
  • Folder loading in path form
  • Third party module

See for more details https://blog.csdn.net/zhangyuan19880606/article/details/51508699

npm

npm is node package manager

./node_module shows all three-party packages installed by node, but the contents of this folder seem to be more than their own install. The reason is that a package may depend on multiple packages during install, so all packages will be downloaded from node_ It's hard to see which packages are installed in the module folder. We hope to have a "manual" in the directory to tell us what packages are installed. The method is to enter npm init according to the prompt after creating the project folder

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (XX) # Fill in the project name here, and press enter to default the name in brackets
version: (1.0.0) # Write the version number here
description: # Write project description here
entry point: (index.js) # Write the entry js file here
test command: # Package release related direct enter
git repository:  # github warehouse address direct enter
keywords: # Keyword direct enter
author: # Project author
license: (ISC) # Open source protocol
About to write to /.../package.json:

{
  ...
}


Is this OK? (yes)

Successfully created package json
After that, the installed package will write relevant information to

"dependencies": {
  "art-template": "^4.13.2",
  "jquery": "^3.5.1"
}

A package lock will also be created during install JSON file, which will display all package and file dependencies. Adding -- save during NPM install will write the dependencies to the file (it can not be written after 5.0 +). For example

npm install jquery
nom install art-template --save
"jquery": {
  "version": "3.5.1",
  "resolved": "https://registry.npm.taobao.org/jquery/download/jquery-3.5.1.tgz",
  "integrity": "sha1-17TQjhv9uGrS8aPQOeoXMEcXq7U="
},

"art-template": {
  "version": "4.13.2",
  "resolved": "https://registry.npm.taobao.org/art-template/download/art-template-4.13.2.tgz",
  "integrity": "sha1-TEy9RN4IqtAxZgJAhx9Fx9c3z8E=",
  "requires": {
    "acorn": "^5.0.3",
    "escodegen": "^1.8.1",
    "estraverse": "^4.2.0",
    "html-minifier": "^3.4.3",
    "is-keyword-js": "^1.0.3",
    "js-tokens": "^3.0.1",
    "merge-source-map": "^1.0.3",
    "source-map": "^0.5.6"
  }
},

We have no node in one_ In the module environment, you only need npm installnode to automatically download dependencies through two json files

package.json and package lock JSON differences:
package.json defines the version range (such as ^ 1.0.0). The specific version installed when running npm install can only be determined after parsing. The dependency tree defined in this can be called logical tree. node_ The modules folder is the specific version of NPM actually installed. The folder structure in this folder can be called physical tree. There are some de duplication algorithms in the installation process, so you will find that the logical tree structure is not exactly the same as the physical tree structure. package-lock.json can be understood as a snapshot that combines the logical tree and physical tree in pairs. There are clear dependent version numbers, actual installation structure and logical tree structure. The biggest advantage is that you can get repeatable build s. When you build repeatedly on CI (continuous integration), the artifact s you get are the same, because the dependent versions are locked. After npm5, its content is the same as NPM shrinkwrap JSON is as like as two peas.
package-lock.json is the specific source and version number of the library currently installed in the generated system, and the locked version.
When you execute npm install, node will start from package Read all dependencies information in the JSON file, and then compare it with node according to the information in dependencies_ Compare the modules in modules. If there is no direct download, the node is from package JSON file to read the module name from package lock Get the version number from the JSON file, and then download or update it.
When package JSON and package lock JSON does not exist. When "npm install XXXX" is executed, node will regenerate package lock JSON file, and then put node_ All module information in modules is recorded in package lock JSON file. However, package. Is not generated JSON file. However, you can generate a package by "npm init --yes" JSON file

To sum up, package JSON needs to init when creating the project. When install ing, it must - save, package lock JSON is generated automatically. If both are left, it can help us build the same node_module environment

The above describes the commands of npm, and nom is also a command-line tool
View version

npm --version

Upgrade npm

npm install --global npm

Skip wizard init

npm init -y

Download package (i is the abbreviation of instal - S is the abbreviation of – save)

npm i -S <name>

Deleting a package does not delete dependencies

npm unstall <name>

Delete package delete dependency

npm unstall --save <name>

help

npm --help

Help of XXX command

npm XXX --help

There are many orders

At the same time, npm is also a website name, and all three-party packages are from the npm website

Using npm

As we all know, the npm server is abroad, so the network speed is slow. You can only use the cnpm of the domestic Taobao mirror station, which is updated every 10min
The installation method is relatively simple

npm install --global cnpm

– global means to install cnpm for all folders
After that, you just need to replace all npm with cnpm. However, the installation prompt of cnpm is different from that of npm. There is no progress bar, but it does not affect it. After using cnpm, you will download files directly from Taobao

If you don't want to install cnpm, you can install it directly

npm install XXXX -g --registry=https://registry.npm.taobao.org

XXXX is the package name to install
If you don't want to install cnpm and don't want to write the website, you can

npm config set register https://registry.npm.taobao.org

File operation path and module identification

In file operation/ The path can be omitted, for example/ tmp/a.cc can be written as tmp/a.cc
In module operation/ Can not be omitted, but js can be omitted
/Represents the root directory of the disk

Express start

The HTTP of native node is not enough to meet our development needs in some aspects, so we need some frameworks to speed up our development efficiency, which is the purpose of the framework
There are many frameworks in node that we can choose express This is a fast, lightweight node JS framework

Simple use

The installation method is

npm install express --save

It's easy to get started. Compare it with what I wrote before
Lead bag

var express = require("express");

Create service program (and HTTP. Createserver)

var app=express();

Callback function when the server receives a get request and the url is ` / '

app.get("/",function(req,res){
    // send returns information, but the previous res.write-res.end can still be used
    res.send("Hello")
})

Request split

// Note that you can accept / submit / submit at this time? 123=456&789=456...
app.get("/submits",function(req,res){
    // It is directly the same as the query of the url module true
    console.log(req.query);
    res.send("Hello")
})

The callback function when the server receives the get request and the url is ` / about '. Note that we don't need to write the file header at this time

app.get("/about",function(req,res){
    // send return information
    // You don't need utf8 here, and you can't see charset in the resources received by the browser. You can see zh CN in accept language, and sometimes you can see that charset when sending web pages
    res.send("about about")
})

The public specified directory is preceded by the url and followed by the folder, which directly realizes the function of the previous public file

app.use('/public/',express.static('./public/'));
// Browser direct access http://127.0.0.1:3000/public/demo.css

Load listening

app.listen(3000,function(){
    console.log("working");
})

Combining the previous code in its own order is the open folder project written before

It can also be used in express art-template

Express automatic restart service

It realizes the automatic restart of express and node server after modifying the code, and its name is nodemon
Installation method:

sudo npm install --global nodemon

After that, when starting the node service, you need to add the node app JS to nodemon app js

route

You can think of routers. Routing is app The process of get ("/") opens the access path for this page. The function of routing is to tell "where the path is". In other words, routing is a set of mapping relationships. Analyze the URL and map the accessed content to the actual action or controller.
That is, app Get ("/", function() {}) is to execute the corresponding callback function when the server gets / requests
app.get("/",function() {}) can only get the request of get, app Post ("/", function() {}) can obtain the post request

Public folder

The url in front of the specified directory and the folder behind it directly realize the function of exposing the file and adding the file header, for example

app.use("/public/",express.static("./public"));

Users can do the following access

  • Demo under public htmlhttp://127.0.0.1:3000/public/demo.html
  • public/demo2/demo3.txthttp://127.0.0.1:3000/public/demo2/demo3.txt

When the first parameter is omitted, it can be accessed directly, for example

app.use(express.static("./public"));

Users can do the following access

  • Demo under public html127. 0.0.1:3000/demo. html
  • public/demo2/demo3.txthttp://127.0.0.1:3000/demo2/demo3.txt

Both methods are acceptable, but the first method is more common because there is an extreme example

app.get("/demo",function(req,res){
    res.send("???")
})

app.use(express.static("./public"));

Yes/ There is also a demo file under public / and the page will display???

app.use(express.static("./public"));

app.get("/demo",function(req,res){
    res.send("???")
})

Yes/ There is also a demo file under public / and the page will display the contents of the public/demo file

Finally, please note that the first parameter is the first few characters of the url, and the second parameter is the physical path. They are not required to be the same

Finally, there is another way to write

app.use('./static',express.static(path.join(__dirname,"public")))

That's what the express document says
However, you provide express The path of the static function is relative to the directory where you started the node process. If you run Express App from another directory, it is safer to use the absolute path of the directory to be served. It can be understood that the first is the relative path writing method, and the second is the absolute path writing method.

  • __ dirname is an absolute path
  • path.join() is the splicing path syntax
  • var path=require("path") (core module) is required

express rewrites the message is to display, replace data with data Tostring() will be improved, but it is still possible to download the file version

How to send a pure static web page?

If you use the previous method

app.get("/post",function(req,res){
    fs.readFile("./views/post.html",function(error,data){
        if(error){
            res.render("404.html");
            return;
        }
        res.send(data);
    })
})

Inexplicably, the website files will be downloaded directly without
You can use this method

app.get("/post",function(req,res){
  fs.readFile("./views/post.html",function(error,data){
      if(error){
          res.render("404.html");
          return;
      }
      res.sendFile(__dirname+"/views/post.html");
  })
})

Note that if you still download the file directly after correction, F12 network disablecharge
However, this method requires that the path should be written completely, which is troublesome. You can use the API of the template engine

Template engine of express

Note that there is no concept of template engine in native http. You need to use, for example, art template to load the template engine and use template Render to render
Express provides interfaces for all template engines. As long as you connect the template engine interface with the template engine, you can work directly with the express method
Therefore, note that in express, we use the express method for rendering, but these methods are implemented by the template engine

Using the art template template template engine

  1. Install the express version of art template
npm install --save art-template
npm install --save express-art-template
  1. Link the interface of express template engine with the implementation of art template template engine (activate the template engine interface defined by express)
app.engine('art', require('express-art-template'));

This sentence means that once the template engine interface of express encounters a file at the end of art, it will use the template engine of art, but I don't like to use the suffix of art, because the highlight is gone (send file is not a template engine interface, it's just an ordinary web page)

app.engine('html', require('express-art-template'));

The express art template in the above code is the express integrated version of art template, which depends on the art template package when running

  1. Send render file
    In native http, we are
var htmls=template.render(data.toString(),{
  comments:comments
});
res.end(htmls);

Render the file first, and then send the rendering results back

res.render('index.html',{comments:comments});

Now we directly call the render method of res of express (the res variable accepts the element from express.get, so it is the express element, not the template element like the element). This method sees an app engine('art', require('express-art-template')); Then activate and see index html is the end of the html format mentioned above, so you can directly use art to render according to the above declaration, and then send the rendering result back

As you can see, I didn't specify index The specific path of HTML is because the author of express (because render is the express method) agreed to store all static page files in/ Under views, so the program directly looks under the folder. If it is to be changed, use this command

app.set("views","Default path")
  • Use this api to send pure static pages
    Now we know that we can use the render of express for page rendering. The premise of using the render method for page rendering is to specify app in advance engine('html', require('express-art-template')); It tells express to directly link the native rendering interface to art for rendering when an HTML file calls this rendering command
    Therefore, the page can be rendered and sent. The express method is used to process all the time, but the implementation of art is called. Therefore, we can also put an html file without any art command into the rendering without writing the second parameter. In this way, once the render is an html file and meets the requirements, it is directly thrown to art. Once art sees that there is no need to process, it returns directly, Render sees the return direct output of art

Note that all interface definitions are express rather than art. You can modify the request of engine and use other engines, but the syntax remains the same (because it does not depend on the engine), and even you can write it to the engine yourself

  1. Perfect event handling function

The previous element http used on("quest",function() {}) uniformly
But in express, get and post are separated. The difference in HTML is

The two most commonly used methods for request response between client and server are GET and POST.

  • GET - requests data from the specified resource.
  • POST - submit the data to be processed to the specified resource

Obviously, we use post best, so we write

app.post("/hahaha",function(req,res){
    console.log("OK")
})

It means that when 127.0.0.1/haha receives the post data, the operation is to output OK under the console. We need to modify the HTML to

- <form action="/commit" method="get">
+ <form action="/hahaha" method="post">

Note that / hahaha should be aligned up, but we can change hahaha to the path of the web page / post, which is more unified. At the same time, the previous page loading function is get("/post",...) And this post("/post",...) No conflict

After that, improve the content in the post, because the two request methods are different, which are

Get : 127.0.0.1:3000/commit/?name1=value1&name2=value2
Post: 127.0.0.1:3000/commit

The content of post is not displayed, so you can't use req Query() to obtain content, we need express plug-in (called Middleware) to obtain the content of post and install it with npm

npm install body-parser

If you write these three lines in the file header, req will have one more The body property gets the Object of the post data

var bodyParser=require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
//...
app.post("/post",function(req,res){
  console.log(req.body)
})

Modify get

- app.get("/commit",function(req,res){
+ app.post("/post",function(req,res){
-   var datas=req.query;
+   var datas=req.body;
    datas.dateTime=new Date().toString();
    comments.push(datas);
    res.redirect('/')
})

Get the final result
Under views, only post is modified HTML file 23 lines

<form action="/post" method="post">

The public file has not been modified

var express=require("express");
var fs=require("fs");
var bodyParser=require("body-parser");
var app=express();
// When rendering files ending in art, use the art template template template engine. Express art template is the express integrated version of art template and depends on the art template package
app.engine('html', require('express-art-template'));
// app.set("views", "default path")
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())


var comments=[{name:"origin",message:"ORIGIN",dateTime:"2020-02-02"}]

app.get("/",function(req,res){
    fs.readFile("./views/index.html",function(error,data){
        if(error){
            res.render("404.html");
            return;
        }
        // The first parameter cannot be written to the path. By default, it will be found in the viewers, and the express convention will put the html in the view folder
        res.render('index.html',{comments:comments});
    })
})

app.get("/post",function(req,res){
    fs.readFile("./views/post.html",function(error,data){
        if(error){
            res.render("404.html");
            return;
        }
        res.render("post.html")
        // res.send(data.toString())
    })
})

// app.get("/commit",function(req,res){
//     var datas=req.query;
//     datas.dateTime=new Date().toString();
//     comments.push(datas);
//     res.redirect('/')
// })

// Both are posts, but the website happens to be a post. At the same time, the front is get(post) and this' post(post) 'do not have the same name
app.post("/post",function(req,res){
    var datas=req.body;
    datas.dateTime=new Date().toString();
    comments.push(datas);
    res.redirect('/')
})

app.use("/public/",express.static("./public"));

app.listen(3000,function(){
    console.log("Working...");
})

CRUD start

Draw the page

  1. Go to BootStrap Download a template use
  2. Binding data
var fs=require("fs");
var express=require("express");
var app=express();
// Load rendering engine
app.engine("html",require("express-art-template"))

// This is a traditional object defined in js
var titleArry=[
    {lab:"Apple",cont:"poor taste"},
    {lab:"Banana",cont:"poor taste"},
    {lab:"mineral water",cont:"yummy"},
    {lab:"peanut",cont:"yummy"}
]

// Access root element
app.get("/",function(req,res){
    // Add utf-8 when reading file, so you don't have to write data ToString, so data is a string directly
    fs.readFile("./db.json","utf8",function(err,dat){
        if(err)
            return res.status(500).send("server error");
            // Reading error returns 500 status code, and then sends the server error
        res.render("index.html",{
            // The first one returned is the object, and the second one is the object: string to JSON object, and then to student
            titleArry:titleArry,
            stus:JSON.parse(dat).student
        });
    })
    
});

// Public documents
app.use("/public/",express.static("./public/"))

app.listen(3000,function(){
    console.log("liuzihao shabi")
})

JSON files are as follows

{
    "student":[
        {"id":1, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":2, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":3, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":4, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":5, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":6, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"},
        {"id":7, "name":"Zhang San", "gender":0, "age":18, "hobbits":"having dinner,sleep,Beat beans"}
    ]
}

Lines 86-121 of html

<div class="row placeholders">
  {{each titleArry}}
  <div class="col-xs-6 col-sm-3 placeholder">
    <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
    <h4>{{$value.lab}}</h4>
    <span class="text-muted">{{$value.cont}}</span>
  </div>
  {{/each}}
</div>

<h2 class="sub-header">Section title</h2>

<a type="button" class="btn btn-success">Add student</a>

<div class="table-responsive">
  <table class="table table-striped">
    <thead>
      <tr>
        <th>#</th>
        <th>full name</th>
        <th>Gender</th>
        <th>Age</th>
        <th>hobby</th>
      </tr>
    </thead>
    <tbody>
      {{each stus item}}
      <tr>
        {{each item item1}}
          <td>{{item1}}</td>
        {{/each}}
      </tr>
      {{/each}}
    </tbody>
  </table>
</div>
  • Note the method of double loop nested named variables in html files
    $value $index
{{each titleArry}}
<div class="col-xs-6 col-sm-3 placeholder">
  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
  <h4>{{$value.lab}}</h4>
  <span class="text-muted">{{$value.cont}}</span>
</div>
{{/each}}

Double specifying variable name

{{each stus item}}
<tr>
  {{each item item1}}
    <td>{{item1}}</td>
  {{/each}}
</tr>
{{/each}}

Routing design

Request methodrouteget parameterpost parameterremarks
GET/student-Render home page
GET/student/new-Add student page
POST/studentForm Data Add student request
GET/student/editidModify student page
POST/student/editForm Data Modify student request
POST/student/delete-Delete student page

Create routing table

We hope to put all routing files in one folder for our management, but we still hope to put the original app JS as the entry of the main program
router.js

module.exports=function(app){
  app.get("/student/new",function(req,res){
    ...
  });
  ...
}

app.js

vat router=require("./router");
router(app);

This method is OK, but express provides a simpler way to realize the encapsulation operation of routing (mainly highlighting and code prompt)

Write the file in router normally, declare it in the file header normally, and add

var router=express.Router();

This creates a routing container
After that, we mount the functions that need to be routed to the routing container, that is, the original app Replace get / post with router gey/post

router.get("/student/new",function(req,res){
  ...
});

Finally, you need to export the container

module.exports=router;

On app JS

app.use(router)

At this point, app JS code becomes

var fs=require("fs");
var router=require("./router.js");
var express=require("express");
var app=express();
app.engine("html",require('express-art-template'));

app.use("/public/",express.static("./public/"))
app.use(router)

app.listen(3000,function(){
    console.log("liuzihao shabi")
})

router.js

var fs=require("fs");
var express=require("express");
// Create a routing container
var router=express.Router();
// Mount the route to the router
router.get("/student",function(req,res){
    // Except data ToString method
    fs.readFile("./db.json","utf8",function(err,dat){
        if(err)
            return res.status(500).send("server error");
        res.render("index.html",{
            titleArry:titleArry,
            stus:JSON.parse(dat).student
        });
    })
    
});
// Export router
module.exports=router;

So we realized modularization

  • app. The task of JS becomes
    • Start service
    • Configure services
      • template engine
      • Configuration of body parser parsing
      • Set static resources
      • Mount routing
      • monitor
  • router.js task becomes
    • Process routing
    • Set the path according to different requests

Encapsulate RUID function

If you want to get the calculation result of an asynchronous function, you also need an asynchronous callback function

function fn(){
  var data;
  setTimeOut(function(){
    var data=0;
  },1000)
  return data;
}

console.log(fn())

We want to get the return value of data=0, but we can't get it because when executing fn(), data is defined first, and then the timer is executed. The timer is an asynchronous function. It is directly thrown into the event queue, and then directly return, such as console Data will change after log
Therefore, to defeat asynchronous functions with asynchronous functions, we can define a remote asynchronous function and let it execute asynchronous functions after modification

Generally, the incoming callback function is used to obtain the contents of asynchronous functions

function fn(callback){
  var data;
  setTimeOut(function(){
    var data=0;
    callback(data);
  },1000)
  return data;
}

fn(function(data){console.log(data)});

You may worry about closures, for example

var item=150

function fn(callback){
    var item=50;
    setTimeout(function(){
        callback()
    },1000);
}

fn(function(){
    console.log("VAL ",item);
})

Rest assured, because the function is an object, the transfer function is the transfer address, so the function is still executed in fn. The above result is VAL 150, or console Log (this) shows global

According to this method, we can realize the function of finding all data

router.get("/student",function(req,res){
    ruid.FindAll(function(error,students){
        if(error)
            return res.status(500).send("SERVER ERROR");
        res.render("index.html",{
            students:students
        });
    })
})
module.exports.Add=function(stu,feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        var stus=JSON.parse(dat).student;
        stus.push(stu);
        fs.writeFile("./DB.json",JSON.stringify({student:stus}),function(error){
            if(error){feedbback(error);return;}
            feedbback(null)
        })
    })
}

Similarly, other requests can be realized. It is worth noting that

  • object has no foreach function, only in
  • Can use
res=arry.find(function(item){
  return item.xx===xx
})

The result of find is the object. res is the object when the xx of the item element in the array satisfies xxx. Note that the object is a pointer and can be operated directly on the array Don't forget to write return
Similarly, findIndex gets the subscript

  • Sometimes we want to post elements in a web page that cannot be modified by users. We can use hidden form elements, such as
<input type="hidden" name="id" value="{{student.id}}">
  • Check whether the incoming number is a string to prevent the occurrence of string===number

All codes

index.js

var fs=require("fs");
var express=require("express");
var bodyParser=require("body-parser");
var router=require("./router")
var app=express();
app.engine("html",require("express-art-template"));
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

app.use("/public/",express.static("./public"));
app.use(router)

app.listen(3000,function(){
    console.log("Working...")
})

router.js

var fs=require("fs");
var express=require("express");
var bodyPares=require("body-parser");
var ruid=require("./ruid")
var router=express.Router();

/** Router
 *  Get   /student        index.html
 *  Get   /student/new    new.html
 *  Post  /student/new    id name sex age hobby
 *  Get   /student/edit   id
 *  post  /student/edit   student
 *  Get   /student/delete id
 */

/** RUID
 *  Add(student)
 *  Del(id)
 *  FindAll()
 *  FindID(id)
 *  Upd(stu)
 */

var nowID = 3;

router.get("/",function(req,res){
    res.send("Welcom");
});

router.get("/student",function(req,res){
    ruid.FindAll(function(error,students){
        if(error)
            return res.status(500).send("SERVER ERROR");
        res.render("index.html",{
            students:students
        });
    })
})

router.get("/student/new",function(req,res){
    res.render("new.html");
})

router.post("/student/new",function(req,res){
    var studnet = req.body;
    studnet.id=++nowID;
    ruid.Add(studnet,function(error){
        if(error)
            return res.status(500).send("SERVER ERROR");
        res.redirect("/student");
    })
})

router.get("/student/edit",function(req,res){
    var id=req.query.id;
    ruid.FindID(id,function(error,dat){
        if(error)
            return res.status(500).send("SERVER ERROR")
        res.render("edit.html",{
            student:dat
        });
    });
})

router.post("/student/edit",function(req,res){
    var stu=req.body;
    ruid.Upd(stu,function(error){
        if(error)
            return res.status(500).send("SERVER ERROR")
        res.redirect("/student")
    });
})

router.get("/student/delete",function(req,res){
    var id=req.query.id;
    ruid.Del(parseInt(id),function(error){
        if(error)
            return res.status(500).send("SERVER ERROR")
        res.redirect("/student")
    });
})

module.exports=router;

ruid.js

const { ifError } = require("assert");
var fs=require("fs");

module.exports.Add=function(stu,feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        var stus=JSON.parse(dat).student;
        stus.push(stu);
        fs.writeFile("./DB.json",JSON.stringify({student:stus}),function(error){
            if(error){feedbback(error);return;}
            feedbback(null)
        })
    })
}

module.exports.Del=function(id,feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        id=parseInt(id);
        var stus=JSON.parse(dat).student;
        var delstu=stus.findIndex(function(item){
            return item.id===id;
        })
        stus.splice(delstu,1);
        fs.writeFile("./DB.json",JSON.stringify({student:stus}),function(error){
            if(error){feedbback(error);return;}
            feedbback(null)
        })
    })
}

module.exports.FindAll=function(feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        var stus=JSON.parse(dat).student;
        feedbback(null,stus);
    })
}

module.exports.FindID=function(id,feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        var stus=JSON.parse(dat).student;
        var fdstu=stus.find(function(item){
            return item.id===parseInt(id)
        })
        feedbback(null,fdstu);
    })
}

module.exports.Upd=function(student,feedbback){
    fs.readFile("./DB.json","utf8",function(err,dat){
        if(err){feedbback(err);return;}
        student.id=parseInt(student.id);
        student.sex=parseInt(student.sex);
        var stus=JSON.parse(dat).student;
        var upstu=stus.find(function(item){
            return item.id===student.id
        })
        for(key in student){
            upstu[key]=student[key]
        }
        fs.writeFile("./DB.json",JSON.stringify({student:stus}),function(error){
            if(error){feedbback(error);return;}
            feedbback(null)
        })
    })
}

index.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Student management system</title>
    <link href="/public/lib/bootstrap.min.css" rel="stylesheet">
    <link href="/public/css/dashboard.css" rel="stylesheet">
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Project name</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">Dashboard</a></li>
                    <li><a href="#">Settings</a></li>
                    <li><a href="#">Profile</a></li>
                    <li><a href="#">Help</a></li>
                </ul>
                <form class="navbar-form navbar-right">
                    <input type="text" class="form-control" placeholder="Search...">
                </form>
            </div>
        </div>
    </nav>
    <div class="container-fluid">
        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                    <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">Reports</a></li>
                    <li><a href="#">Analytics</a></li>
                    <li><a href="#">Export</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item</a></li>
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                    <li><a href="">More navigation</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                </ul>
            </div>
            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                <h2 class="sub-header">Student management system</h2>
                <a type="button" class="btn btn-success" href="/student/new">Add student</a>
                <div class="table-responsive">
                    <table class="table table-striped">
                        <thead>
                            <tr>
                                <th>#</th>
                                <th>Name</th>
                                <th>Sex</th>
                                <th>Age</th>
                                <th>Hobby</th>
                                <th>Option</th>
                            </tr>
                        </thead>
                        <tbody>
                            {{each students student}}
                            <tr>
                                <td>{{student.id}}</td>
                                <td>{{student.name}}</td>
                                <td>{{student.sex}}</td>
                                <td>{{student.age}}</td>
                                <td>{{student.hobby}}</td>
                                <td>
                                    <a href="/student/edit?id={{student.id}}">Edit</a>&nbsp;|&nbsp;
                                    <a href="/student/delete?id={{student.id}}">Delete</a>
                                </td>
                            </tr>
                            {{/each}}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script>
        window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')
    </script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
</body>
</html>

edit.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Student management system</title>
    <link href="/public/lib/bootstrap.min.css" rel="stylesheet">
    <link href="/public/css/dashboard.css" rel="stylesheet">
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Project name</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">Dashboard</a></li>
                    <li><a href="#">Settings</a></li>
                    <li><a href="#">Profile</a></li>
                    <li><a href="#">Help</a></li>
                </ul>
                <form class="navbar-form navbar-right">
                    <input type="text" class="form-control" placeholder="Search...">
                </form>
            </div>
        </div>
    </nav>
    <div class="container-fluid">
        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                    <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">Reports</a></li>
                    <li><a href="#">Analytics</a></li>
                    <li><a href="#">Export</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item</a></li>
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                    <li><a href="">More navigation</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                </ul>
            </div>
            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                <h2 class="sub-header"></h2>
                <form action="/student/edit" method="POST">
                    <input type="hidden" name="id" value="{{student.id}}">
                    <div class="form-group">
                        <label for="exampleInputEmail1">Name</label>
                        <input type="text" class="form-control" name="name" placeholder="name" value="{{student.name}}">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Age</label>
                        <input type="text" class="form-control" name="age" placeholder="age" value="{{student.age}}">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Sex</label>
                        <label class="radio-inline">
                            <input type="radio" name="sex" id="inlineRadio1" value="0" checked="{{!student.sex}}"> male
                        </label>
                        <label class="radio-inline">
                            <input type="radio" name="sex" id="inlineRadio2" value="1" checked="{{student.sex}}"> female
                        </label>
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Hobby</label>
                        <input type="text" class="form-control" name="hobby" placeholder="hobby" value="{{student.hobby}}">
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
            </div>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script>
        window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')
    </script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
</body>

</html>

new.html

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Student management system</title>
    <link href="/public/lib/bootstrap.min.css" rel="stylesheet">
    <link href="/public/css/dashboard.css" rel="stylesheet">
</head>

<body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
                    aria-expanded="false" aria-controls="navbar">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="#">Project name</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#">Dashboard</a></li>
                    <li><a href="#">Settings</a></li>
                    <li><a href="#">Profile</a></li>
                    <li><a href="#">Help</a></li>
                </ul>
                <form class="navbar-form navbar-right">
                    <input type="text" class="form-control" placeholder="Search...">
                </form>
            </div>
        </div>
    </nav>
    <div class="container-fluid">
        <div class="row">
            <div class="col-sm-3 col-md-2 sidebar">
                <ul class="nav nav-sidebar">
                    <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
                    <li><a href="#">Reports</a></li>
                    <li><a href="#">Analytics</a></li>
                    <li><a href="#">Export</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item</a></li>
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                    <li><a href="">More navigation</a></li>
                </ul>
                <ul class="nav nav-sidebar">
                    <li><a href="">Nav item again</a></li>
                    <li><a href="">One more nav</a></li>
                    <li><a href="">Another nav item</a></li>
                </ul>
            </div>
            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
                <h2 class="sub-header"></h2>
                <form action="/student/new" method="POST">
                    <div class="form-group">
                        <label for="exampleInputEmail1">Name</label>
                        <input type="text" class="form-control" name="name" placeholder="name">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Age</label>
                        <input type="text" class="form-control" name="age" placeholder="age">
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Sex</label>
                        <label class="radio-inline">
                            <input type="radio" name="sex" id="inlineRadio1" value="0"> male
                        </label>
                        <label class="radio-inline">
                            <input type="radio" name="sex" id="inlineRadio2" value="1"> female
                        </label>
                    </div>
                    <div class="form-group">
                        <label for="exampleInputEmail1">Hobby</label>
                        <input type="text" class="form-control" name="hobby" placeholder="hobby">
                    </div>
                    <button type="submit" class="btn btn-default">Submit</button>
                </form>
            </div>
        </div>
    </div>
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
    <script>
        window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')
    </script>
    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="../../assets/js/vendor/holder.min.js"></script>
    <script src="../../assets/js/ie10-viewport-bug-workaround.js"></script>
</body>

</html>

DB.json

{
    "student": [{
        "id": 2,
        "name": "Zhang San",
        "sex": 0,
        "age": 18,
        "hobby": "having dinner,sleep,Beat beans"
    }, {
        "id": 3,
        "name": "Zhang San",
        "sex": 1,
        "age": "18",
        "hobby": "having dinner,sleep,Beat beans"
    }, {
        "name": "Liu Kairui",
        "age": "19",
        "sex": 0,
        "hobby": "M",
        "id": 4
    }]
}

Pay attention to the asynchronous programming idea

Content after

  • Node and MongoDB
  • Node and MySQL
  • AJAX for Node
  • Promise/async of Node
  • ES and standardization

Keywords: node.js

Added by silent on Wed, 09 Feb 2022 19:00:49 +0200