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…
- github.com/
-
-
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 routingconst { 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
- src/router/blog.js
-
- 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)
- A cookie is a string stored in the browser (up to 5KB)
- 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
-
- Problems with cookies
3.2 Session Writes redis
- The problem of the session
- SESSION_DATA occupies nodeJS memory
- The memory is overloaded due to heavy traffic
- After the official launch, the system runs multiple processes, and the memory between processes cannot be shared
- SESSION_DATA occupies nodeJS memory
- redis
-
- Data is stored in memory
- Compared to mysql, the access speed is faster
- It costs more and has less data to store
- Data is stored in memory
-
- 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
- Session access is frequent and has high performance requirements
-
- 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
- Operation frequency is not high
-
- 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
- Log content accumulates slowly and cannot be handled in a single file
- 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
- The most primitive and simple attack
5.2 XSS attacks
-
- Attack: In the page display content doping JS code, to obtain webpage information
-
Precaution: Convert generated JS special characters
-
& => & < => < > => > "= > & quot; '= > & # x27; / => /Copy the code
-
blog.js
const xss = require('xss'); const newBlog = (blogData = {}) => { const title = xss(blogData.title) //... } Copy the code
-
- Attack: In the page display content doping JS code, to obtain webpage information
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
- Attack mode: Obtain the user name and password, and then try to log in to other systems
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
- db/redis.js
-
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
- loginCheck.js
-
-
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
- routes/user.js
-
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
- package.json
- 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
- pm2.conf.json