An interface

1.1 Node processes HTTP requests

  • What is the process from entering an address in the browser to displaying it?
    • DNS resolution, establishing TCP connections, and sending HTTP requests
    • The server receives the HTTP request, processes it, and returns it
    • The client receives the returned data, processes it, and renders the page
  • Processing HTTP requests
    • NPM init initializes the project

    • Const HTTP = the require (" HTTP "); Const server = http.createserver ((req, res) => {res.end(" Hello world ")}); server.listen(8000)Copy the code
    • Get request and QueryString

      • index.js

        const http = require("http"); const querystring = require("querystring"); const server = http.createServer((req, res) => { console.log("method: ", req.method); //==> GET const url = req.url; console.log("url: ", url); req.query = querystring.parse(url.split("?" ) [1]); console.log("qurey: ", req.query); res.end(JSON.stringify(req.query)); }); server.listen(8000);Copy the code
      • node index.js

      • Browser visit http://localhost:8000/? a=100&b=200

    • Post requests and Postdata

      • Postman/Chrome plugin emulated POST requests
      • index.js
        const http = require("http"); Const server = http.createserver ((req, res) => {if (req.method === "POST") {// Console. log("content-type:", req.headers["content-type"]); // let postData = ""; req.on("data", (chunk) => { postData += chunk.toString(); }); req.on("end", () => { console.log(postData); res.end("hello world"); }); }}); server.listen(8000);Copy the code
    • routing

        • github.com/
          • github.com/username
          • Github.com/username/XX…
    • Composite sample

      • const http = require("http"); const querystring = require("querystring"); const server = http.createServer((req, res) => { const { method, url } = req; const path = url.split("?" ) [0]; const query = querystring.parse(url.split("?" ) [1]); // Set the return format to JSON res.setheader (" content-type ", "application/ JSON "); // Return data const resData = {method, url, path, query,}; if (method === "GET") { res.end(JSON.stringify(resData)); } if (method === "POST") { let postData = ""; req.on("data", (chunk) => { postData += chunk.toString(); }); req.on("end", () => { resData.postData = postData; res.end(JSON.stringify(resData)); }); }}); server.listen(8000);Copy the code

1.2 Setting up the development environment

  • The Nodemon monitors file changes and automatically restarts the Node

  • Cross-env sets environment variables, compatible with MAC/Window/Linux

  • package.json

    {"main": "bin/www.js", "scripts ": {" dev ":" cross-env NODE_ENV=dev nodemon. /bin/www.js ", "PRD ": Cross-env NODE_ENV=production nodemon./bin/www.js}}Copy the code
    • process.env.NODE_ENV
  • Bin /www.js only cares about the HTTP pure technology layer

    const http = require('http') const serverHandle = require('.. /app') const PORT = 8000 const server = http.createServer(serverHandle) server.listen(PORT)Copy the code
  • app.js

    Const serverHandle = (req, res) => {// Set the return format to JSON res.setheader (' content-type ', 'application/json') // Get path req.path = req.url.split('? Query = queryString.parse (req.url.split('? ') [1])})Copy the code

1.3 Development interface (database is not connected, login is not considered)

  • Initializing a Route
    • app.js

      const handleBlogRouter = require('./src/router/blog') const handleUserRouter = require('./src/router/user') const ServerHandle = (req, res) => {// Set the return format to JSON res.setheader (' content-type ', 'application/ JSON ')}; // Get path const url = req.url; The req. Path = url. Split ('? Query = queryString.parse (req.url.split('? Const blogData = handleBlogRouter(req, res); ')[1]) // Handle blog routing const blogData = handleBlogRouter(req, res); if(blogData){ res.end(JSON.stringify(blogData)); return; } // handle user const userData = handleUserRouter(req, res); if(userData){ res.end(JSON.stringify(userData)); return; } // No route is matched, return 404 res.writeHead(404, {" content-type ":" text-plain "}); Res. Write (" 404 Not Found \ n "); res.end(); } module.exports = serverHandleCopy the code
      • src/router/blog.js

        const handleBlogRouter = (req, Res) => {const method = req.method // GET POST const id = req.query.id // GET the list of blogs if(method === 'GET' && req.path === = '/api/blog/list') { return { msg: 'this is blog list api' } } // ... } module.exports = handleBlogRouterCopy the code
      • src/router/user.js

        const handleUserRouter = (req, Res) => {const method = req.method // GET POST const id = req.query.id // log in if(method === 'POST' &&req.path === = '/ user/login ') {return {MSG: 'this is login API '}} //... } module.exports = handleUserRouterCopy the code
    • SRC /model/ resmodel.js // only care about the state

      class BaseModel { constructor(data, message) { if(typeof data === 'string') { this.message = data data = null message = null } if(data) { this.data = data }  if(message) { this.message = message } } } class SuccessModel extends BaseModel { constructor(data, message) { super(data, message) this.errno = 0 } } class ErrorModel extends BaseModel { constructor(data, message) { super(data, message) this.errno = -1 } } module.exports = { SuccessModel, ErrorModel }Copy the code
      • src/router/blog.js

        // Only care about routing
        const { getList} = require('.. / controller/blog "); const { SuccessModel, ErrorModel } = require('.. / model/resModel "); const handleBlogRouter = (req, Res) => {const method = req.method // GET POST const id = req.query.id // GET the list of blogs if(method === 'GET' && req.path === = '/ API/blog/list') {const author = the req. Query. The author | | '; const keyword = req.query.keyword || '' ; const result = getList(author, keyword) return result.then(listData => { return new SuccessModel(listData) }) } // ... } module.exports = handleBlogRouterCopy the code
  • Return false data
    • SRC /controller/blog.js only cares about the data manipulation database

      Const getList = (author, keyword)=>{return [{id:1, title: "title1", content: "test text", createTime: 1546620491112, author: 'z3'}, //...  } module.exports = { getList }Copy the code
    • app.js

      Const getPostData = (req) => {const promise = new promise (resolve, reject) => {if(req.method! == 'POST') { resolve({}) return } if(req.headers['content-type'] ! == 'application/json') { resolve({}) return } let postData = '' req.on('data', chunk => { postData += chunk.toString() }) req.on('end', () => { if(! postData) { resolve({}) return } resolve( JSON.parse(postData) ) }) }) return promise }Copy the code
      • Const serverHandle = (req, res) => {// Set the return format to JSON res.setheader (' content-type ', 'application/json') // Get path req.path = req.url.split('? Query = queryString.parse (req.url.split('? ')[1]) // Post data getPostData(req).then(postData => {req. Body = postData // Login route const userResult = handleUserRouter(req, Res) if(userResult) {userresult. then(userData => {res.end(json.stringify (userData))}) return} // Process blog route const blogResult = handleBlogRouter(req, Res) if(blogResult) {blogresult. then(blogData => {res.end(json.stringify (blogData))}) return} // No route is hit res.writeHead(404, {'Content-type': 'text/plain'}) res.write('404 Not Found! \n') res.end() }) }Copy the code

MySQL data store

2.1 build library

  • Click the library icon in MySQLWorkbench to create the library

    CREATE SCHEMA `myblog` ;

Table 2.2 built

  • In MySQLWorkbench, myblog > Tables > right-click > create table > users or blogs
  • datatype
    • Varchar (50) length 50
    • Longtext longtext with maximum size of 4G
    • Int integer
    • bigint(20)
  • PK main construction cannot be repeated
  • NN cannot be empty
  • Automatic AI increase
  • Click the apply button to finish

Table 2.3 operation

  • Using SQL statements
    • use myblog; show tables; Error Code: 1175. You are using safe update mode an... Execute SET SQL_SAFE_UPDATES=0Copy the code
  • increase
    •   insert into users(username, `password`, realname) values('zhang3'.'123'.'Joe');  
        insert into users(username, `password`, realname) values('li4'.'123'.'bill');  
      Copy the code
  • delete
    • -- delete delete from users where username='li4'; Update users set state='0' where username='li4'; Select * from users where state<> '0';Copy the code
  • change
    • Update users set realName =" li4 "where username='li4';Copy the code
  • check
    •   Check -
        select * from users;  
        select id, username from users;  
        Select * from 'where'
        select * from users where username="zhang3";  
        select * from users where username="zhang3" and `password`='123';  
        select * from users where username="zhang3" or `password`='123';  
        -- Query like fuzzy query
        select * from users where username like "%zhang%";  
        Select order by order
        select * from users order by id;  
        -- Order desc
        select * from users order by id desc;  
      Copy the code

2.4 Node Operating mySQL

  • npm i mysql

  • index.js

    const mysql = require("mysql");  
      
    // Create a link object
    const con = mysql.createConnection({  
      host: "localhost".user: "root".password: "XXXXXX".port: "3306".database: "myblog"});// Start the connection
    con.connect();  
      
    // Execute the SQL statement
    const sql = "select * fromt users";  
    con.query(sql, (err, result) = > {  
      if (err) {  
        console.error(err);  
        return;  
      }  
      console.log(result);  
    });  
      
    // Close the connection
    con.end();  
    Copy the code
  • Errno: 1064 use mysql; alter user 'root'@'localhost' identified with mysql_native_password by 'XXXXXX'; flush privileges;Copy the code
  • src/conf/db.js

    const env = process.env.NODE_ENV let MYSQL_CONF if(env === 'dev') { MYSQL_CONF = { host: 'localhost', user: 'root', password: 'XXXXXX ', port: '3306', database: 'myblog'}} if(env === 'production') {MYSQL_CONF = {host: 'localhost', user: 'root', password: 'XXXXXX', port: '3306', database: 'myblog' } } module.exports = { MYSQL_CONF }Copy the code
  • src/db/mysql.js

    const mysql = require('mysql') const { MYSQL_CONF } = require('./.. /conf/db') const con = mysql.createconnection (MYSQL_CONF) const con = mysql.createconnection (MYSQL_CONF) const con = mysql.createconnection (MYSQL_CONF exec(sql) { const promise = new Promise((resolve, reject) => { con.query(sql, (err, result) => { if(err) { reject(err) return } resolve(result) }) }) return promise } module.exports = { exec }Copy the code

2.5 connecting apis to mySQL

  • SRC /controller/blog.js only cares about the data manipulation database

    const { exec } = require('./.. /db/mysql') const getList = (author, keyword) => { let sql = `select * from blogs where 1=1 ` if(author) { sql += `and anthor='${author}' ` } if(keyword) { sql += `and title like '%${keyword}%' ` } sql += `order by createtime desc; ` return exec(sql) } // ... module.exports = { getList }Copy the code
  • SRC /router/blog.js // only care about routing

    const { getList} = require('.. / controller/blog "); const { SuccessModel, ErrorModel } = require('.. / model/resModel "); const handleBlogRouter = (req, Res) => {const method = req.method // GET POST const id = req.query.id // GET the list of blogs if(method === 'GET' && req.path === = '/ API/blog/list') {const author = the req. Query. The author | | '; const keyword = req.query.keyword || '' ; const result = getList(author, keyword) return result.then(listData => { return new SuccessModel(listData) }) } // ... } module.exports = handleBlogRouterCopy the code
  • app.js

    const handleBlogRouter = require('./src/router/blog') const serverHandle = (req, res) => { // ... Const blogData = handleBlogRouter(req, res); if(blogData){ res.end(JSON.stringify(blogData)); return; // Handle user // failed route, return 404} module.exports = serverHandleCopy the code

Three login

3.1 the cookie and session

  • cookie
      • A cookie is a string stored in the browser (up to 5KB)
        • Not shared across domains
        • Formats such as k1 = v1; k2=v2; k3=k3; Therefore, structured data can be stored
        • Each time an HTTP request is sent, the cookie of the request domain is sent to the server
        • The server can modify the cookie and return it to the browser
        • Cookies can also be modified using JS in the browser (with limitations)
    • JS operating cookie
      • // add document.cookie = 'k1=100; 'Copy the code
    • The server operates cookies
      • // Parse cookie req.cookie = {}; const cookieStr = req.headers.cookie || ""; // console.log(cookieStr); cookieStr.split(";" ).map(item => { if (! item) return; const arr = item.split("="); const key = arr[0].trim(); const value = arr[1].trim(); req.cookie[key] = value; });Copy the code
      • Use httpOnly to limit front-end changes to cookies, and expires to set an expiration time

        res.setHeader( "Set-Cookie", `userid=${userId}; path='/'; httpOnly; expires=${getCookieExpires()}` );Copy the code
    • Cookie Login Process
      • 1. The front-end sends the username password in cookie to the back-end. 2. 3. Verify successfully. Write cookies to userID and set httpOnly and Expires to front-end 4. When the front end visits the back end, the browser will automatically take userID cookid 5. The backend verifies the userID to determine whether to log in
  • session
    • Problems with cookies
      • Problem: Expose username, dangerous. Solution: The userID can be stored in the cookie, and the server corresponds to the username — this is session
    • Session code example
      • // session data const SESSION_DATA = {};Copy the code
      • Session let needSetCookie = false; let userId = req.cookie.userid; if (userId) { if (! SESSION_DATA[userId]) { SESSION_DATA[userId] = {}; } } else { needSetCookie = true; userId = `${Date.now()}_${Math.random()}`; SESSION_DATA[userId] = {}; } req.session = SESSION_DATA[userId];Copy the code
      • The router/user.js backend sets user data to req.session to ensure security

        If (method === "POST" &&req. path === "/ API /user/login") {const {username, password} = req.body; const result = login(username, password); Return result.then(data => {if (data.username) {// Set session req.session.username = data.username; req.session.realname = data.realname; return new SuccessModel(data); } return new ErrorModel(" login failed "); }); }Copy the code

3.2 Session Writes redis

  • The problem of the session
    • SESSION_DATA occupies nodeJS memory
      1. The memory is overloaded due to heavy traffic
      2. After the official launch, the system runs multiple processes, and the memory between processes cannot be shared
  • redis
      • Data is stored in memory
        • Compared to mysql, the access speed is faster
        • It costs more and has less data to store
  • Why is Sessin suitable for Redis
      • Session access is frequent and has high performance requirements
        • Session does not consider loss of data due to power outages
        • The amount of session data is not too large
  • Why is site data not redis
      • Operation frequency is not high
        • Power outages cannot be lost, they must be preserved
        • Too much data and too high memory cost
  • Redis basis
    • The installation

      brew install redis  
      Copy the code

      Start the server

      redis-server  
      Copy the code

      Start the cli redis – cli

      set get

      Set myname zhang3 get myname Query all keys delete key del mynameCopy the code

3.3 Develop the login function node link redis

  • demo
    • npm i redis --save
    •   const redis = require('redis')  
          
        const client = redis.createClient(6379.'127.0.0.1');  
          
        client.on('error'.err= >{  
            console.error(err)  
        })  
          
        client.set('myname'.'zhangsan2',redis.print)  
        client.get('myname'.(err,val) = >{  
            if(err){  
                console.log(err);  
                return;  
            }  
            console.log('val:',val);  
            client.quit()  
        })  
      Copy the code
  • Encapsulating tool function
    • config/db.js

      // let REDIS_CONF if (env === 'dev') {REDIS_CONF = {port: 6379, host: '127.0.0.1'}} if (env === 'production') {redis REDIS_CONF = {port: 6379, host: '127.0.0.1'}} module.exports = {REDIS_CONF}Copy the code
    • db/redis.js

      const redis = require("redis");  
      const { REDIS_CONF } = require(".. /config/db");  
        
      // Create client without quit() because it is singleton mode
      const client = redis.createClient(REDIS_CONF.port, REDIS_CONF.host);  
      client.on("error".err= > {  
        console.error(err);  
      });  
        
      const set = (key, val) = > {  
        if (typeof val === "object") {  
          // We need val to be a string
          val = JSON.stringify(val);  
        }  
        client.set(key, val, redis.print);  
      };  
        
      const get = key= > {  
        const promise = new Promise((resolve, reject) = > {  
          client.get(key, (err, val) = > {  
            if (err) {  
              reject(err);  
              return;  
            }  
            // Return null if no data is retrieved
            if (val === void 0) {  
              resolve(null);  
              return;  
            }  
            // Try catch is for compatibility with json.parse
            try {  
              resolve(JSON.parse(val));  
            } catch(error) { resolve(val); }}); });return promise;  
      };  
        
      module.exports = {  
        set,  
        get  
      };  
      Copy the code
    • router/blog.js

      const loginCheck = req= > {  
        console.log("req.session",req.session);  
        if(! req.session.username) {return Promise.resolve(  
            new ErrorModel('Not logged in'))}}// Create a new blog interface
        if (method === "POST" && req.path === "/api/blog/new") {  
        
          const loginCheckResult = loginCheck(req)  
          if (loginCheckResult) {  
            / / not logged in
            return loginCheckResult  
          }  
          / / have to log in
          req.body.author = req.session.username / / false data
          const result = newBlog(req.body)  
          return result.then(data= > {  
            return new SuccessModel(data)  
          })  
        }  
      Copy the code
    • app.js

      const { get, set } = require("./src/db/redis");  
        
      // Parse session (using redis)
        let needSetCookie = false;  
        let userId = req.cookie.userid;  
        console.log("userId", userId);  
        if(! userId) { needSetCookie =true;  
          userId = `The ${Date.now()}_The ${Math.random()}`;  
          // Initializes session initialization in Redis
          set(userId, {});  
        }  
        // Create a sessionId attribute for req,
        req.sessionId = userId;  
        get(req.sessionId)  
          .then((sessionData) = > {  
            if(! sessionData) {// Initializes session initialization in Redis
              set(req.sessionId, {});  
              / / set the session
              req.session = {};  
            } else {  
              req.session = sessionData;  
            }  
            return getPostData(req);  
          })  
          .then((postData) = > {  
            req.body = postData;  
            const blogResult = handleBlogRouter(req, res);  
            if (blogResult) {  
              blogResult.then((blogData) = > {  
                if (needSetCookie) {  
                  res.setHeader(  
                    "Set-Cookie".`userid=${userId}; path='/'; httpOnly; expires=${getCookieExpires()}`  
                  );  
                }  
                res.end(JSON.stringify(blogData));  
              });  
              return;  
            }  
            const userResult = handleUserRouter(req, res);  
        
            if (userResult) {  
              userResult.then((userData) = > {  
                if (needSetCookie) {  
                  res.setHeader(  
                    "Set-Cookie".`userid=${userId}; path='/'; httpOnly; expires=${getCookieExpires()}`  
                  );  
                }  
                res.end(JSON.stringify(userData));  
              });  
              return;  
            }  
            // Failed route: 404 is returned
            res.writeHead(404, {  
              "Content-type": "text/plain"}); res.write("404 Not Found\n");  
            res.end();  
          });  
      Copy the code

Four log

4.1 Log Types

  • Access log
  • Custom logging (including custom events, error logging, and so on)

4.2 Node File Operation stream

  • const fs = require("fs"); const path = require("path"); const fileName = path.resolve(__dirname, "data.jon.txt"); // read file fs.readFile(fileName, (err, data) => { if (err) { console.error(err); return; } // Data is binary and needs to be converted to the string console.log(data.tostring ()); }); // write file const content = "new content\n"; Const opt = {flag: "a", // append, w}; fs.writeFile(fileName, content, opt, (err) => { if (err) { console.error(err); return; }}); // exists fs.exists(fileName, (exist) => { console.log(exist); });Copy the code
    • pipe

      const path = require("path")  
      const fs = require("fs")  
        
      const fileName1 = path.resolve(__dirname,'data.txt')  
      const fileName2 = path.resolve(__dirname,'data-back.txt')  
        
      const readSteam = fs.createReadStream(fileName1)  
      const writeSteam = fs.createWriteStream(fileName2)  
        
      readSteam.pipe(writeSteam)  
      readSteam.on('data',chunk=>{  
          console.log(chunk.toString());  
      })  
      readSteam.on('end',()=>{  
          console.log("copy done");  
      })  
      Copy the code
    •   const http = require('http');  
        const path = require("path")  
        const fs = require("fs")  
        const fileName1 = path.resolve(__dirname,'data.txt')  
        const server = http.createServer((req, res) = >{  
            if(the req. Method = = = "GET") {const readSteam = fs.createReadStream(fileName1)  
                readSteam.pipe(res)  
            }  
        })  
        server.listen(8000)  
      Copy the code

4.3 Developing and Using the Log Function

  • src/logs/access.log

    src/logs/error.log

    src/logs/event.log

  • src/utils/log.js

    const path = require('path')  
    const fs = require("fs")  
      
    / / write logs
    function writeLog(writeStream, log) {  
        writeStream.write(log + '\n')}/ / generated writeStream
    function createWriteStream(fileName) {  
        const fullFileName = path.join(__dirname, ".. /.. /logs/", fileName)  
        const writeStream = fs.createWriteStream(fullFileName, {  
            flags: 'a'  
        })  
        return writeStream;  
    }  
      
    // Write access logs
    const accessWriteStream = createWriteStream('access.log')  
      
    function access(log) {  
        writeLog(accessWriteStream, log)  
    }  
      
    module.exports = {  
        access  
    }  
    Copy the code
  • src/app.js

    const serverHandle = (req, res) = > {  
      // Log access
      access(  
        `${req.method} -- ${req.url} -- ${  
          req.headers["user-agent"]} -- The ${Date.now()}`  
      );  
    / /...
    Copy the code

4.4 Splitting log files and analyzing log content

    • Log content accumulates slowly and cannot be handled in a single file
      • Log files by time: 2020-10-10.access.log
      • Implementation method: Run the crontab command on Linux
  • crontab
    • To set a scheduled task, go to *****command
    • Copy and rename access.log to 2020-10-10.access.log
    • Clear the access.log file and continue to accumulate logs
    • ! Log cp access.log $(data +%Y-%m-%d).access.log echo "" > access.logCopy the code
  • Log analysis
    • For example, analyze the ratio of Chrome to access.log logs
    • Logs are stored in rows, and a row is a log
    • Readline using NodeJS (Stream-based, efficient)
    • src/utils/readline.js
      const fs = require("fs");  
      const path = require("path");  
      const readline = require("readline");  
        
      / / file name
      const fileName = path.join(__dirname, ".. /.. /logs"."access.log");  
      // Create read Stream
      const readStream = fs.createReadStream(fileName);  
        
      // Create a radline object
      const rl = readline.createInterface({  
        input: readStream,  
      });  
        
      let chromeNum = 0;  
      let sum = 0;  
        
      // Read line by line
      rl.on("line".(lineData) = > {  
        if(! lineData) {return;  
        }  
        // Record the total number of rows
        sum++;  
        
        const arr = lineData.split("--");  
        if (arr[2] && arr[2].indexOf("Chrome") > 0) {  
          // Add chrome numberchromeNum++; }}); rl.on("close".() = > {  
        console.log("Chrome ratio:" + chromeNum / sum);  
      });  
      Copy the code

Five safety

* Server side attacks are very many, prevention means are also very many

  • This article covers only the common ones that can be prevented at the Web Server (NodeJS) level
  • Some attacks require hardware and services to support (OP support is required), such as DDOS

5.1 SQL injection

    • The most primitive and simple attack
      • Attack method: Enter a SQL fragment, eventually spliced into a piece of attack code
      • Precaution: Use mysql’s escape function to process input
      •   const mysql = require('mysql')  
          const login = (username, password) = > {  
            username = mysql.escape(username);  
            password = mysql.escape(password);  
            // ...  
          };  
        Copy the code

5.2 XSS attacks

    • Attack: In the page display content doping JS code, to obtain webpage information
      • Precaution: Convert generated JS special characters

      • & => &amp; < => &lt; > => &gt; "= > & quot; '= > & # x27; / => &#x2f;Copy the code
      • blog.js

        const xss = require('xss');  
        const newBlog = (blogData = {}) => {  
          const title = xss(blogData.title)  
          //...  
        }  
        
        Copy the code

5.3 Password Encryption

    • Attack mode: Obtain the user name and password, and then try to log in to other systems
      • Precaution: Encrypt your password
      • const crypto = require("crypto"); // const SECRET_KEY = "AbEdQe_123#$"; Function md5(content) {let md5 = crypto.createHash("md5"); return md5.update(content).digest("hex"); } // function genPassword(password) {const STR = 'password=${password}&key=${SECRET_KEY}'; return md5(str); }Copy the code

Use Express for refactoring

6.1 Middleware Principles

  • NPM I express-generator-g create directory Express blog- Express

    package.json

    Scripts :{dev: cross-env NODE_ENV=dev nodemon./bin/ WWW}Copy the code
  •   app.use((req, res, next) = > {  
        console.log("Request to commence...", req.method, req.url);  
        next();  
      });  
        
      app.use('/api'.(req, res, next) = >{  
        console.log('Process/API routing')  
        next()  
      })  
        
      app.get("/api/get-cookit".(req, res, next) = > {  
        console.log("Get/API/get-Cookit routing");  
        res.json({ erron: 0.data: "ok" });  
      });  
        
      app.post("/api/get-post-data".(req, res, next) = > {  
        console.log("Post/API /get-post-data routing");  
        res.json({ erron: 0.data: "ok" });  
      });  
        
      app.use((req, res, next) = > {  
        / / 404
        res.json({ erron: 1.data: 404 });  
      });  
        
        
        
    Copy the code
    • Concatenate by next()
    • Many-sum functions can be passed
      app.get("/api/get-cookit", loginCheck, (req, res, next) = > {  
        console.log("Get/API/get-Cookit routing");  
        res.json({ erron: 0.data: "ok" });  
      });  
        
      Copy the code

6.2 Using middleware Mechanisms

  • app.js

    Cookie var cookieParser = require('cookie-parser'); // Parse JSON POST data and mount it to req.body app.use(express.json()); // Parse non-JSON formats, mount to req.body app.use(express.urlencoded({extended: false}));Copy the code
  • App. Js log

    / / record log
    var logger = require('morgan');  
      
    const ENV = process.env.NODE_ENV;  
    if(ENV ! = ="production") {  
      // Development environment/test environment
      app.use(logger("dev"));  
    } else {  
      // Online environment
      const logFileName = path.join(__dirname, "logs"."access.log");  
      const writeStream = fs.createWriteStream(logFileName, {  
        flags: "a"}); app.use( logger("combined", {  
          stream: writeStream,  
        })  
      );  
    }  
    Copy the code
    • The development environment outputs to the console online environment outputs to access.log
  • app.js session

    // session redis  
    const session = require('express-session')  
    const RedisStore = require('connect-redis')(session)  
      
    const redisClient = require("./db/redis");  
    const sessionStore = new RedisStore({  
      client: redisClient,  
    });  
    app.use(  
      session({  
        secret: "WJiol#23123_".cookie: {  
          // path: '/', // Default configuration
          // httpOnly: true, // default configuration
          maxAge: 24 * 60 * 60 * 1000,},store: sessionStore,  
      })  
    );  
    Copy the code
    • db/redis.js
      const redis = require('redis')  
      const { REDIS_CONF } = require('.. /conf/db.js')  
        
      // Create a client
      const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)  
      redisClient.on('error'.err= > {  
          console.error(err)  
      })  
        
      module.exports = redisClient  
      Copy the code
  • app.js router

    const userRouter = require('/ routes/user "); app.use('/api/user', userRouter);  
    Copy the code
    • routes/index.js

      var express = require('express');  
      var router = express.Router();  
        
      // Add '/ API /blog/list' to app.useThe router. The get (/ list,function(req, res, next) {  
        res.json({ errno: 0.data:’OK’ });  
      });  
      Copy the code
    • routes/user.js

      var express = require('express');  
      var router = express.Router();  
      const { login } = require('.. /controller/user')  
      const { SuccessModel, ErrorModel } = require('.. /model/resModel')  
        
      router.post('/login'.function(req, res, next) {  
          const { username, password } = req.body  
          const result = login(username, password)  
          return result.then(data= > {  
              if (data.username) {  
                  / / set the session
                  req.session.username = data.username  
                  req.session.realname = data.realname  
        
                  res.json(  
                      new SuccessModel()  
                  )  
                  return  
              }  
              res.json(  
                  new ErrorModel('Login failed'))})});module.exports = router;  
      Copy the code
    • router/blog.js

      const loginCheck = require('.. /middleware/loginCheck')  
      router.post('/new', loginCheck, (req, res, next) = > {  
          req.body.author = req.session.username  
          const result = newBlog(req.body)  
          return result.then(data= > {  
              res.json(  
                  new SuccessModel(data)  
              )  
          })  
      })  
      Copy the code
      • loginCheck.js
        const { ErrorModel } = require('.. /model/resModel')  
          
        module.exports = (req, res, next) = > {  
            if (req.session.username) {  
                next()  
                return  
            }  
            res.json(  
                new ErrorModel('Not logged in'))}Copy the code
  • app.js 404

    // Optimize 404 page prompt text
    var createError = require('http-errors');  
    app.use(function(req, res, next) {  
      next(createError(404));  
    });  
    Copy the code

6.3 Middleware Implementation Roadmap

  • Analysis of the
    • Register via app.use
    • When encountering an HTTP request, determine which to trigger based on path and method
    • Implement the next mechanism where the previous one triggers the next one through next

Use Koa2 for reconstruction

7.1 development koa2

  • The installation

    npm i koa-generator -g  
    Koa2 koa2-test  
    npm i & npm run dev  
    Copy the code
  • App. Js to log in

    const session = require('koa-generic-session')  
    const redisStore = require('koa-redis')  
    const user = require('./routes/user')  
      
    / / the session configuration
    app.keys = ['WJiol#23123_']  
    app.use(session({  
      / / configuration cookies
      cookie: {  
        path: '/'.httpOnly: true.maxAge: 24 * 60 * 60 * 1000  
      },  
      / / configure redis
      store: redisStore({  
        // all: '127.0.0.1:6379' // write local redis to death
        all: `${REDIS_CONF.host}:${REDIS_CONF.port}`  
      })  
    }))  
      
    app.use(user.routes(), user.allowedMethods())  
    Copy the code
    • routes/user.js
      const router = require('koa-router') ()const { login } = require('.. /controller/user')  
      const { SuccessModel, ErrorModel } = require('.. /model/resModel')  
      // Route prefix
      router.prefix('/api/user')  
        
      router.post('/login'.async function (ctx, next) {  
          const { username, password } = ctx.request.body  
          const data = await login(username, password)  
          if (data.username) {  
              / / set the session
              ctx.session.username = data.username  
              ctx.session.realname = data.realname  
              // return the front-end data
              ctx.body = new SuccessModel()  
              return  
          }  
          ctx.body = new ErrorModel('Login failed')})module.exports = router  
      Copy the code
  • app.js logger

    const logger = require('koa-logger')  
    const path = require('path')  
    const fs = require('fs')  
    const morgan = require('koa-morgan')  
      
    // logger  
    app.use(async (ctx, next) => {  
      const start = new Date(a)await next()  
      const ms = new Date() - start  
      console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)})const ENV = process.env.NODE_ENV  
    if(ENV ! = ='production') {  
      // Development environment/test environment
      app.use(morgan('dev'));  
    } else {  
      // Online environment
      const logFileName = path.join(__dirname, 'logs'.'access.log')  
      const writeStream = fs.createWriteStream(logFileName, {  
        flags: 'a'  
      })  
      app.use(morgan('combined', {  
        stream: writeStream  
      }));  
    }  
    Copy the code

7.2 Analysis of KOA2 Middleware

8 Online Configuration

8.1 Online environment challenges

  • Server stability
  • Take full advantage of server hardware resources to improve performance
  • Online logging

8.2 PM2 can solve the above problems

  • Daemon process, system crash automatic restart
  • Start multiple processes to make full use of CPU and memory
  • Provides the log recording function

8.3 PM2

  • Download and install
    •   npm i pm2 -g  
        pm2 --version  
      Copy the code
  • The basic use
    • package.json
      "scripts": {  
          "prd": "cross-env NODE_ENV=production pm2 start bin/www",},Copy the code
  • Common commands
    • pm2 start app.js
    • pm2 list
    • pm2 restart <AppName>/<id>
    • pm2 stop <AppName>/<id>
    • pm2 delete <AppName>/<id>
    • pm2 info <AppName>/<id>
    • pm2 log <AppName>/<id>
    • pm2 moint <AppName>/<id>
  • The process to protect
    • Simulation error

      if(the req. Url = = = '/ err) {throw new Error()}Copy the code
    • Pm2 list Indicates that the restart is restarted

      Pm2 log app Uses the PM2 log to view logs and analyze causes

  • Commonly used configuration
    • pm2.conf.json
      {  
          "apps": {  
              "name": "pm2-test-server"."script": "app.js"."watch": true."ignore_watch": [  
                  "node_modules"."logs"]."instances": 4./ / process
              "error_file": "logs/err.log"."out_file": "logs/out.log"."log_date_format": "YYYY-MM-DD HH:mm:ss"}}Copy the code