Skip to content

LaughSun0513/node-learning-paths

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

38 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Node-Blog

Node + Express/Koa2 + PM2 + MySQL/Redis

Nodejs็œŸๆญฃ็”จ้€”

  • Nodejs๏ผŒไธ€ไธชjs่ฟ่กŒ็Žฏๅขƒ
  • ่ฟ่กŒๅœจๆœๅŠก็ซฏ๏ผŒไฝœไธบweb server
  • ่ฟ่กŒๅœจๆœฌๅœฐ๏ผŒไฝœไธบๆ‰“ๅŒ…๏ผŒๆž„ๅปบๅทฅๅ…ท

ๅญฆไน ็›ฎๆ ‡ -- ไธชไบบๅšๅฎข็ณป็ปŸ

ๅญฆไน ๅ†…ๅฎน

  • API
  • ๆ•ฐๆฎๅญ˜ๅ‚จ
  • ็™ปๅฝ•
  • ๆ—ฅๅฟ—
  • ๅฎ‰ๅ…จ

ๆŠ€ๆœฏ

  • HTTP
  • Stream
  • Session
  • MySQL/Redis
  • Nginx
  • PM2

็Ÿฅ่ฏ†็‚นไป‹็ป

่ฏพ็จ‹ๅ‡†ๅค‡

  • Nodeไป‹็ป --- Nodeๅฎ‰่ฃ… Nodeๅ’ŒjsๅŒบๅˆซ
  • ๆœๅŠก็ซฏ็‰น็‚น--- ๆœๅŠก็ซฏ็‰น็‚น ๆœๅŠก็ซฏๅ’Œๅ‰็ซฏ็š„ๅŒบๅˆซ
  • ๆกˆไพ‹ๅˆ†ๆžๅ’Œ่ฎพ่ฎก--- ๅšๅฎข้กน็›ฎ็š„้œ€ๆฑ‚ๅˆ†ๆžๅ’ŒๆŠ€ๆœฏๆ–นๆกˆ่ฎพ่ฎก

  1. ไฝฟ็”จๅŽŸ็”Ÿไปฃ็ ๅผ€ๅ‘ๆกˆไพ‹้กน็›ฎ
  • ๅฎž็ŽฐAPIๅ’Œๆ•ฐๆฎๅญ˜ๅ‚จ๏ผŒไฝฟ็”จMySQLๆ•ฐๆฎๅบ“
  • ไปŽ0ๅฎž็Žฐ็™ปๅฝ•๏ผŒๅนถไฝฟ็”จredisๅญ˜ๅ‚จ็™ปๅฝ•ไฟกๆฏ
  • ๅฎ‰ๅ…จ๏ผŒๆ—ฅๅฟ—่ฎฐๅฝ•ๅ’Œๆ—ฅๅฟ—ๅˆ†ๆž

  1. ไฝฟ็”จๆก†ๆžถๅผ€ๅ‘ๆกˆไพ‹้กน็›ฎ
  • ๅˆ†ๅˆซไฝฟ็”จexpress ๅ’ŒKoa2
  • ไธญ้—ดไปถๆœบๅˆถ
  • ๅธธ็”จๆ’ไปถ
  • ไธญ้—ดไปถๅŽŸ็†

  1. ็บฟไธŠ็Žฏๅขƒ
  • PM2ไป‹็ปๅ’Œ้…็ฝฎ
  • PM2ๅคš่ฟ›็จ‹ๆจกๅž‹
  • ๅ…ณไบŽๆœๅŠกๅ™จ่ฟ็ปด

ๅŽŸ็”Ÿไปฃ็ 

  • APIๅ’Œๆ•ฐๆฎๅญ˜ๅ‚จ
  • ็™ปๅฝ•ๅ’ŒRedis
  • ๅฎ‰ๅ…จๅ’Œๆ—ฅๅฟ—

ไฝฟ็”จๆก†ๆžถ

  • Express ๅ’Œ Koa2
  • ไธญ้—ดไปถๅ’Œๆ’ไปถ
  • ไธญ้—ดไปถๅŽŸ็†

็บฟไธŠ็Žฏๅขƒ

  • PM2ไป‹็ปๅ’Œ้…็ฝฎ
  • PM2ๅคš่ฟ›็จ‹ๆจกๅž‹
  • ๆœๅŠกๅ™จ่ฟ็ปด

Nodeไป‹็ป

ไธ‹่ฝฝๅ’Œๅฎ‰่ฃ…

1.ๆ™ฎ้€šๆ–นๅผ nodejs.cn ๅฎ˜็ฝ‘ 2.NVM node็‰ˆๆœฌ็ฎก็†ๅทฅๅ…ท Mac brew install nvm Window githubๆœnvm-windows

nvm list # ๆŸฅ็œ‹ๅฝ“ๅ‰ๆ‰€ๆœ‰็š„node็‰ˆๆœฌ
nvm install v10.15.0 # ๅฎ‰่ฃ…ๅˆถๅฎš็‰ˆๆœฌ
nvm use --delete-prefix 10.13.0 # ๅˆ‡ๆขๅˆฐๆŒ‡ๅฎš็‰ˆๆœฌ

Nodeๅ’Œๅ‰็ซฏjsๅŒบๅˆซ

  • ESMAScript -- ่ฏญๆณ•่ง„่Œƒ

    ๅฎšไน‰ไบ†่ฏญๆณ• ๏ผŒๅ†™js็š„nodeๅฟ…้กป้ตๅฎˆ ๅ˜้‡ๅฎšไน‰๏ผŒๅพช็Žฏ๏ผŒๅˆคๆ–ญ๏ผŒๅ‡ฝๆ•ฐ ๅŽŸๅž‹ๅ’ŒๅŽŸๅž‹้“พใ€ไฝœ็”จๅŸŸๅ’Œ้—ญๅŒ…ใ€ๅผ‚ๆญฅ ไธ่ƒฝๆ“ไฝœDOM๏ผŒไธ่ƒฝ็›‘ๅฌclickๆ—ถ้—ด๏ผŒไธ่ƒฝๅ‘้€ajax่ฏทๆฑ‚ ไธ่ƒฝๅค„็†http่ฏทๆฑ‚๏ผŒไธ่ƒฝๆ“ไฝœๆ–‡ไปถ ๅชๆœ‰ESMAScript๏ผŒๆ— ๆณ•ๅš้กน็›ฎ

  • Javascript

    ไฝฟ็”จESMAScript่ฏญๆณ•่ง„่Œƒ๏ผŒๅค–ๅŠ Web API๏ผŒ็ผบไธ€ไธๅฏ๏ผˆESMAScript + Web API๏ผ‰ DOMๆ“ไฝœ๏ผŒBOM๏ผŒไบ‹ไปถ๏ผŒAjax... ไธค่€…็ป“ๅˆ๏ผŒๅณๅฏๅฎŒๆˆๆต่งˆๅ™จ็ซฏ็š„ๆ“ไฝœ

  • NodeJs

    ไฝฟ็”จESMAScript่ฏญๆณ•่ง„่Œƒ๏ผŒๅค–ๅŠ Node API๏ผŒ็ผบไธ€ไธๅฏ๏ผˆESMAScript + Node API๏ผ‰ ๅค„็†http๏ผŒๅค„็†ๆ–‡ไปถ็ญ‰API ไธค่€…็ป“ๅˆ๏ผŒๅณๅฏๅฎŒๆˆserver็ซฏ็š„ๆ“ไฝœ

  • ่กฅๅ……:Commonjs & Node debugger

  • Commonjs

# ๅฏผๅ‡บ
  module.exports = ๅ˜้‡
  module.exports = ๅฏน่ฑก

# ๅผ•ๅ…ฅ1
  const {a,b} = require('./a); //่งฃๆž„ๅผ•ๅ…ฅ

# ๅผ•ๅ…ฅ2
  const opt = require('./a);
  const a = opt.a
  const b = opt.b
  • Node bugger ๅˆฉ็”จvscode่‡ชๅธฆ็š„debuggerๅŠŸ่ƒฝ๏ผŒไผšๆ นๆฎpackage.json ้‡Œ็š„ mainๅญ—ๆฎตๅŽปๆ‰พๅ…ฅๅฃ

serverๅผ€ๅ‘ๅ’Œๅ‰็ซฏๅผ€ๅ‘็š„ๅŒบๅˆซ

ๆœๅŠก็จณๅฎšๆ€ง

  • server ็ซฏๅฏ่ƒฝไผš้ญๅ—ๅ„็งๆถๆ„ๆ”ปๅ‡ปๅ’Œ่ฏฏๆ“ไฝœ
  • ๅ•ไธชๅฎขๆˆท็ซฏๅฏไปฅๆ„ๅค–ๆŒ‚ๆމ๏ผŒไฝ†ๆ˜ฏๆœๅŠก็ซฏไธ่ƒฝ
  • ๅฏไปฅไฝฟ็”จPM2ๅš่ฟ›็จ‹ๅฎˆๆŠค

่€ƒ่™‘ๅ†…ๅญ˜ๅ’ŒCPU๏ผˆไผ˜ๅŒ–ๅ’Œๆ‰ฉๅฑ•๏ผ‰

  • ๆ—ฅๅฟ—่ฎฐๅฝ•
  • ๅฎ‰ๅ…จ
  • ้›†็พคๅ’ŒๆœๅŠกๆ‹†ๅˆ†

้กน็›ฎ

็›ฎๆ ‡

  • ๅผ€ๅ‘ๅšๅฎข็ณป็ปŸ๏ผŒๅ…ทๆœ‰ๅšๅฎข็š„ๅŸบๆœฌๅŠŸ่ƒฝ
  • ไน‹ๅผ€ๅ‘server็ซฏ๏ผŒไธๅ…ณๅฟƒๅ‰็ซฏ

้œ€ๆฑ‚

  • ้ฆ–้กตใ€ไฝœ่€…ไธป้กตใ€ๅšๅฎข่ฏฆๆƒ…้กต
  • ็™ป้™†้กต
  • ็ฎก็†ไธญๅฟƒใ€ๆ–ฐๅปบ้กตใ€็ผ–่พ‘้กต

ๆŠ€ๆœฏๆ–นๆกˆ

1. ๆ•ฐๆฎๅฆ‚ไฝ•ๅญ˜ๅ‚จ

  • ๅšๅฎข
id title content createtime author
1 ๆ ‡้ข˜1 ๅšๅฎข1 ๅˆ›ๅปบๆ—ถ้—ดxxx-xxx-xxx xxx
2 ๆ ‡้ข˜2 ๅšๅฎข2 ๅˆ›ๅปบๆ—ถ้—ดxxx-xxx-xxx2 xxx2
  • ็”จๆˆท
id username password realname
1 zhangsan 123 ๅผ ไธ‰
2 lisi 456 ๆŽๅ››

2. ๅฆ‚ไฝ•ไธŽๅ‰็ซฏๅฏนๆŽฅ๏ผŒๅณๆŽฅๅฃ่ฎพ่ฎก

ๆ่ฟฐ ๆŽฅๅฃ ๆ–นๆณ• urlๅ‚ๆ•ฐ ๅค‡ๆณจ
่Žทๅ–ๅšๅฎขๅˆ—่กจ /api/blog/list get authorไฝœ่€…๏ผŒkeywordๆœ็ดขๅ…ณ้”ฎๅญ— ๅ‚ๆ•ฐไธบ็ฉบ๏ผŒๅˆ™ไธ่ฟ›่กŒๆŸฅ่ฏข่ฟ‡ๆปค
่Žทๅ–ไธ€็ฏ‡ๅšๅฎข็š„ๅ†…ๅฎน /api/blog/detail get id
ๆ–ฐๅขžไธ€็ฏ‡ๅšๅฎข /api/blog/new post postไธญๆœ‰ๆ–ฐๅขž็š„ไฟกๆฏ
ๆ›ดๆ–ฐไธ€็ฏ‡ๅšๅฎข /api/blog/update post id postDataไธญๆœ‰ๆ›ดๆ–ฐ็š„ๅ†…ๅฎน
ๅˆ ้™คไธ€็ฏ‡ๅšๅฎข /api/blog/del post id
็™ปๅฝ• /api/user/login post postDataไธญๆœ‰็”จๆˆทๅๅ’Œๅฏ†็ 

3. ๅ…ณไบŽ็™ปๅฝ•

  • ไธš็•Œๆœ‰็ปŸไธ€็š„่งฃๅ†ณๆ–นๆกˆ๏ผŒไธ€่ˆฌไธ็”จๅ†้‡ๆ–ฐ่ฎพ่ฎก

ๅผ€ๅ‘ๆŽฅๅฃ

nodejsๅค„็†http่ฏทๆฑ‚

DNS่งฃๆž ๅปบ็ซ‹TCP่ฟžๆŽฅ ๅ‘้€http่ฏทๆฑ‚

- ๅŸŸๅ -- > ip+port

serverๆŽฅๆ”ถๅˆฐhttp่ฏทๆฑ‚๏ผŒๅค„็†๏ผŒๅนถ่ฟ”ๅ›ž

get ่ฏทๆฑ‚ๅ’Œquerystring

  • get่ฏทๆฑ‚๏ผŒๅณๅฎขๆˆท็ซฏ่ฆๅ‘server็ซฏ่Žทๅ–ๆ•ฐๆฎ๏ผŒๅฆ‚ๆŸฅ่ฏขๅšๅฎขๅˆ—่กจ
  • ้€š่ฟ‡querystringไผ ้€’ๆ•ฐๆฎ๏ผŒๅฆ‚ a.html?a=100&b=200
  const http = require('http');
  const querystring = require('querystring');

  const server = http.createServer((req,res)=>{
      console.log(req.method)
      const url = req.url;
      console.log(url);

      const queryStr = url.split('?')[1]; //ๆ นๆฎ้—ฎๅทๆ‹†ๅˆ†ๅ‚ๆ•ฐ
      req.query = querystring.parse(queryStr);
      res.end(JSON.stringify(req.query));
  });
  server.listen(8000);

post ่ฏทๆฑ‚ๅ’Œpostdata๏ผˆpostๅ‘้€็š„ๆ•ฐๆฎ๏ผ‰

- ๅฎขๆˆท็ซฏๅ‘ๆœๅŠก็ซฏไผ ้€’ๆ•ฐๆฎ๏ผŒๅฆ‚ๆ–ฐๅปบๅšๅฎข
- ้€š่ฟ‡post dataไผ ้€’ๆ•ฐๆฎ
- ๆต่งˆๅ™จๆ— ๆณ•็›ดๆŽฅๆจกๆ‹Ÿ๏ผŒ้œ€่ฆๆ‰‹ๅ†™js๏ผŒๆˆ–่€…ไฝฟ็”จpostman
  const http = require('http');
  const log = console.log;

  const server = http.createServer((req,res)=>{
      if(req.method ==="POST"){
        // req ๆ•ฐๆฎๆ ผๅผ
        log('req content-type',req.headers['content-type']);

        // ๆŽฅๆ”ถๆ•ฐๆฎ
        let postData = '';
        req.on('data',chunk=>{
          postData += chunk.toString();
        });
        req.on('end',()=>{
          log('postData',postData);
          res.end('hello post')
        })
      }
  });
  server.listen(8001);
postmanๆจกๆ‹Ÿๅ‘้€post่ฏทๆฑ‚

1.ChromeไธŠๅฎ‰่ฃ…postmanๆ’ไปถ 2.ๅœฐๅ€ๆ ่พ“ๅ…ฅ่ฎฟ้—ฎๅœฐๅ€ http://localhost:8001๏ผŒไฟฎๆ”น่ฏทๆฑ‚ไธบPOST 3.็‚นๅ‡ปไธ‹ๆ–น โ€œBodyโ€ ---> raw ๅณไพง้€‰ๆ‹ฉ JSON ---> ไธ‹ๆ–น็ฉบ็™ฝๅŒบ ่พ“ๅ…ฅ่ฏทๆฑ‚ๅ‚ๆ•ฐjson

่ทฏ็”ฑ

  ่งฃๆžreq.url ้‡Œ็š„/username /password็ญ‰

็ปผๅˆ็คบไพ‹

  const http = require('http');
  const querystring = require('querystring');##
  const log = console.log;

  const server = http.createServer((req,res)=>{
      const method = req.method;
      const url = req.url;
      const query = querystring.parse(url.split('?')[1]);
      const path = url.split('?')[0]

      res.setHeader('Content-type','application/json');

      const resData = {
        method,
        url,
        query,
        path
      }
      if(method==='GET'){
        res.end(JSON.stringify(resData))
      }
      if(method==='POST'){
        let postData = '';
        req.on('data',chunk => {
          postData += chunk
        });
        req.on('end',()=>{
          log('postData',postData);
          resData.postData = postData
          res.end(JSON.stringify(resData));
        })
      }
  });
  server.listen(8002);

ๅฎขๆˆท็ซฏๆŽฅๆ”ถๅˆฐ่ฟ”ๅ›žๆ•ฐๆฎ๏ผŒๅค„็†ๆ•ฐๆฎ๏ผˆๅฆ‚ๆธฒๆŸ“้กต้ข๏ผŒๆ‰ง่กŒjs๏ผ‰

ๆญๅปบๅผ€ๅ‘็Žฏๅขƒ

  • ไปŽ0ๅผ€ๅง‹ๆญๅปบ๏ผŒไธไฝฟ็”จไปปไฝ•ๆก†ๆžถ
  • ไฝฟ็”จnodemon็›‘ๆต‹ๆ–‡ไปถๅ˜ๅŒ–๏ผŒ่‡ชๅŠจ้‡ๅฏnode
  • ไฝฟ็”จcross-env ่ฎพ็ฝฎ็Žฏๅขƒๅ˜้‡๏ผŒๅ…ผๅฎนmac/linux/windows

ๅผ€ๅ‘ๆŽฅๅฃ๏ผŒๆš‚ไธ่€ƒ่™‘่ฟžๆŽฅๆ•ฐๆฎๅบ“ๅ’Œ็™ปๅฝ•

  • ๅˆๅง‹ๅŒ–่ทฏ็”ฑ๏ผšๆ นๆฎไน‹ๅ‰ๆŠ€ๆœฏๆ–นๆกˆ็š„่ฎพ่ฎก๏ผŒๅšๅ‡บ่ทฏ็”ฑ
  • ่ฟ”ๅ›žๅ‡ๆ•ฐๆฎ๏ผšๅฐ†่ทฏ็”ฑๅ’Œๆ•ฐๆฎๅˆ†็ฆป๏ผŒไปฅ็ฌฆๅˆ่ฎพ่ฎกๅŽŸๅˆ™
โ”œโ”€โ”€ app.js  -- ไธป่ฆๆœๅŠก   
โ”œโ”€โ”€ bin
โ”‚   โ””โ”€โ”€ www.js --- ๅˆ›ๅปบๆœๅŠก 
โ”œโ”€โ”€ controllers --- ๆ”พๅ‡ๆ•ฐๆฎ 
โ”‚   โ””โ”€โ”€ index.js
โ”œโ”€โ”€ models  --- ่ฟ”ๅ›žๆญฃ็กฎ/้”™่ฏฏ ็ปŸไธ€ๆ•ฐๆฎๆ ผๅผ  Model     
โ”‚   โ””โ”€โ”€ index.js
โ”œโ”€โ”€ package-lock.json
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ routers -- ่ทฏ็”ฑๆ–‡ไปถ๏ผŒ่งฃๆž่ฏทๆฑ‚  
    โ”œโ”€โ”€ blog.js
    โ””โ”€โ”€ user.js
# blog.js
const handleBlogRouter = (req,res) =>{
    const method = req.method;
    const path = req.url.split('?')[0];
  
    //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/blog/list
    if( method==="GET" && path === "/api/blog/list"){
        return {
          msg:'/api/blog/list'
        }
    }
    //่Žทๅ–ไธ€็ฏ‡ๅšๅฎข็š„ๅ†…ๅฎน  /api/blog/detail
    if( method==="GET" && path === "/api/blog/detail"){
        return {
          msg:'/api/blog/detail'
        }
    }
    //ๆ–ฐๅขžไธ€็ฏ‡ๅšๅฎข   /api/blog/new 
    if( method==="POST" && path === "/api/blog/new"){
        return {
          msg:'/api/blog/new'
        }
    }
    //ๆ›ดๆ–ฐไธ€็ฏ‡ๅšๅฎข   /api/blog/update  
    if( method==="POST" && path === "/api/blog/update"){
      return {
        msg:'/api/blog/update'
      }
    }
    //ๅˆ ้™คไธ€็ฏ‡ๅšๅฎข   /api/blog/del   
    if( method==="POST" && path === "/api/blog/update"){
      return {
        msg:'/api/blog/update'
      }
    }
}
module.exports = handleBlogRouter;
# user.js
const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.url.split('?')[0];

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="POST" && path === "/api/user/login"){
      return {
        "msg":"/api/user/login"
      }
  }
  
}
module.exports = handleUserRouter;
# app.js
const handleBlogRouter= require('./routers/blog');
const handleUserRouter = require('./routers/user');

const serverHandle = (req,res) => {
    //่ฎพ็ฝฎ่ฟ”ๅ›ž็š„JSON
    res.setHeader('Content-type','application/json');
    const blogData = handleBlogRouter(req,res);
    if(blogData){
      res.end(JSON.stringify(blogData));
    }

    const userData = handleUserRouter(req,res);
    if(userData){
      res.end(JSON.stringify(userData));
    }
    
}

module.exports = serverHandle;

่งฃๆžpost่ฏทๆฑ‚็š„ๆŽฅๅฃ ๅ’Œ ไบ†่งฃ callback/promise/async&await

# app.js
const queryString = require('querystring');
const handleBlogRouter= require('./routers/blog');
const handleUserRouter = require('./routers/user');

//่งฃๆžpost data๏ผŒ่ฟ”ๅ›žpromiseๅฏน่ฑก
const getPostData = (req) => {
    const promise = new Promise((resolve,reject) => {
          if(req.method === "POST" && req.headers['content-type'] === 'application/json'){
            let postData = "";
            req.on('data',chunk => postData += chunk.toString());
            req.on("end",()=>{
              if(postData){
                resolve(JSON.parse(postData));
              }else{
                resolve({});
                return;
              }
            })
          }else{
            resolve({});
            return;
          }
    });
    return promise;
}

const serverHandle = (req,res) => {
    //่ฎพ็ฝฎ่ฟ”ๅ›ž็š„JSON
    res.setHeader('Content-type','application/json');
    //่Žทๅ–path
    const url = req.url;
    req.path = url.split('?')[0];
    req.query = queryString.parse(url.split('?')[1])

    //่งฃๆžpostๆ•ฐๆฎ
    getPostData(req).then(postData => {
        req.body = postData;
        //ๅค„็†ๅšๅฎข็š„่ทฏ็”ฑ
        const blogData = handleBlogRouter(req,res);
        if(blogData){
          res.end(JSON.stringify(blogData));
        }

        //ๅค„็†็”จๆˆท็™ปๅฝ•็š„่ทฏ็”ฑ
        const userData = handleUserRouter(req,res);
        if(userData){
          res.end(JSON.stringify(userData));
        }
    })
    
    
}

module.exports = serverHandle;
# ๅปบ็ซ‹่ฟ”ๅ›ž็š„ๆ•ฐๆฎๆ ผๅผModel models/index.js
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
}
# ่งฃๆž ๅšๅฎข่ทฏ็”ฑ routers/blog.js
const {
  getList,
  getDetail,
  newBlog,
  updateBlog,
  delBlog
} = require('../controllers/blog')
const { SuccessModel,ErrorModel }  = require('../models')
const handleBlogRouter = (req,res) =>{
    const method = req.method;
    const path = req.path;
    const query = req.query;
    const id = query && query.id;
   

    //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/blog/list
    if( method==="GET" && path === "/api/blog/list"){
        const { author , keyword } = query;
        if(author && keyword){
          const resData = getList(author,keyword);
          return new SuccessModel(resData);
        }else {
          return new ErrorModel('่Žทๅ–ๅšๅฎขๅˆ—่กจๅคฑ่ดฅ๏ผŒ่ฏทไผ ๆญฃ็กฎ็š„ๅ‚ๆ•ฐ author & keyword');
        }
        
    }
    //่Žทๅ–ไธ€็ฏ‡ๅšๅฎข็š„ๅ†…ๅฎน  /api/blog/detail
    if( method==="GET" && path === "/api/blog/detail"){
        if(id){
          const resData = getDetail(id);
          return new SuccessModel(resData);
        }else{
          return new ErrorModel('่Žทๅ–ๅšๅฎขๅ†…ๅฎนๅคฑ่ดฅ๏ผŒ่ฏทไผ ๆญฃ็กฎ็š„ๅ‚ๆ•ฐid');
        }
    }
    //ๆ–ฐๅขžไธ€็ฏ‡ๅšๅฎข   /api/blog/new 
    if( method==="POST" && path === "/api/blog/new"){
        const resData = newBlog(req.body);
        return new SuccessModel(resData);
    }
    //ๆ›ดๆ–ฐไธ€็ฏ‡ๅšๅฎข   /api/blog/update  
    if( method==="POST" && path === "/api/blog/update"){
      const resData = updateBlog(id,req.body);
      if(resData){
        return new SuccessModel('ๆ›ดๆ–ฐๅšๅฎขๆˆๅŠŸ');
      }else {
        return new ErrorModel('ๆ›ดๆ–ฐๅšๅฎขๅคฑ่ดฅ')
      }
    }
    //ๅˆ ้™คไธ€็ฏ‡ๅšๅฎข   /api/blog/del   
    if( method==="POST" && path === "/api/blog/del"){
      if(id){
        const resData = delBlog(id);
        if(resData){
          return new SuccessModel('ๅˆ ้™คๅšๅฎขๆˆๅŠŸ');
        }
      }
    }
}
module.exports = handleBlogRouter;
# ่งฃๆž็”จๆˆท็™ปๅฝ•่ทฏ็”ฑ routers/user.js
const { loginCheck } = require('../controllers/user');
const { SuccessModel,ErrorModel }  = require('../models')
const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.path;

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="POST" && path === "/api/user/login"){
     const { username,password } = req.body;
     const result = loginCheck(username,password);
     if(result){
      return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
     }
     return new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!');
  }
  
}
module.exports = handleUserRouter;
# ๅค„็†ๆ•ฐๆฎ controllers/blog.js
const getList = (author,keyword) => {
    console.log(author,keyword)
    return [
      {
        id:1,
        title:'ๅšๆ–‡A',
        content:"ๅ†…ๅฎนA",
        author:"zhangsan"
      },
      {
        id:2,
        title:'ๅšๆ–‡B',
        content:"ๅ†…ๅฎนB",
        author:"lisi"
      }
    ]
}
const getDetail = (id) => {
  return {
        id:1,
        title:'ๅšๆ–‡A',
        content:"ๅ†…ๅฎนA",
        author:"zhangsan"
  }
}
const newBlog = (blogData = {}) => {
  return {
    id:3
  }
}
const updateBlog = (id,blogData = {}) => {
    // id ่ฆๆ›ดๆ–ฐ็š„ๅšๅฎขid
    // blogData ๅšๅฎขๅฏน่ฑก ๅŒ…ๅซtitle contentๅฏน่ฑก
    console.log('update blog',id,blogData);
    return true;
}
const delBlog = (id) => {
  //id ่ฆๅˆ ้™ค็š„ๅšๅฎขid
   return true;
}
module.exports = {
  getList,
  getDetail,
  newBlog,
  updateBlog,
  delBlog
}
# ๅค„็†ๆ•ฐๆฎ controllers/user.js
const loginCheck = (username,password) => {
  if(username === 'zhangsan' && password === '123'){
    return true;
  }
  return false;
}
module.exports = {
  loginCheck
}

MySQL

mysql ไป‹็ป ๅฎ‰่ฃ… ไฝฟ็”จ

  • web server ไธญๆœ€ๆต่กŒ็š„ๅ…ณ็ณปๅž‹ๆ•ฐๆฎๅบ“

  • ่ฝป้‡็บง๏ผŒๆ˜“ๅญฆๆ˜“็”จ

  • ๅฎ‰่ฃ…mysql mysql ๆ‰ง่กŒๅฎ‰่ฃ…--->่ฎฐไฝroot็”จๆˆทๅ็š„ๅฏ†็ 

  • ๅฎ‰่ฃ…mysqlๅฏ่ง†ๅŒ–ๅทฅๅ…ท workbench

ๅปบๅบ“--->ๅปบ่กจ--->่กจๆ“ไฝœ

  • ๅฆ‚ไฝ•ๅปบๅบ“๏ผŒๅปบ่กจ
  • ๅปบ่กจๆ—ถๅธธ็”จ็š„ๆ•ฐๆฎ็ฑปๅž‹(int,bight,varchar,longtext)
  • sql ่ฏญๅฅๅฎž็Žฐๅขžๅˆ ๆ”นๆŸฅ
  1. ๅปบๅบ“ --> ๅˆ›ๅปบmyblogๆ•ฐๆฎๅบ“ --> ๆ‰ง่กŒshow databasesๆŸฅ่ฏข
  2. ๅปบ่กจ

ๅˆ›ๅปบblogsๅšๅฎข่กจ

id title content createtime author
1 ๆ ‡้ข˜1 ๅšๅฎข1 ๅˆ›ๅปบๆ—ถ้—ดxxx-xxx-xxx xxx
2 ๆ ‡้ข˜2 ๅšๅฎข2 ๅˆ›ๅปบๆ—ถ้—ดxxx-xxx-xxx2 xxx2

-------------------------blogsๅšๅฎข่กจ็ป“ๆž„่ฎพ่ฎก

column datatype pkไธป้”ฎ nnไธไธบ็ฉบ AI่‡ชๅŠจๅขžๅŠ  Deafult
id int(ๆ•ดๆ•ฐ็ฑปๅž‹) Y(ไธ้‡ๅค) Y Y (่‡ชๅขž)
title varchar(50)(ๅญ—็ฌฆไธฒ) Y
content longtext(20) Y
createtime bigint(20)(้•ฟๆ•ดๆ•ฐ) Y 0
author varchar(50) Y

ๅˆ›ๅปบusers่กจ

id username password realname
1 zhangsan 123 ๅผ ไธ‰
2 lisi 456 ๆŽๅ››

------------------------users็”จๆˆท่กจ็ป“ๆž„่ฎพ่ฎก

column datatype pkไธป้”ฎ nnไธไธบ็ฉบ AI่‡ชๅŠจๅขžๅŠ 
id int(ๆ•ดๆ•ฐ็ฑปๅž‹) Y(ไธ้‡ๅค) Y Y (่‡ชๅขž)
username varchar(20)(ๅญ—็ฌฆไธฒ) Y
password varchar(20) Y
realname varchar(10) Y

3.ๆ“ไฝœ่กจ

# ไฝฟ็”จmyblogๅบ“
use myblog; 

# ๆ˜พ็คบๆ‰€ๆœ‰่กจ
show tables; 
# ๆณจ้‡Š
-- show tables; 

# ๅขž
insert into users (username,`password`,realname) values ('zhangsan','123','ๅผ ไธ‰') # ๅ‘users่กจๆ’ๅ…ฅusername,`password`ๅ…ณ้”ฎ่ฏๅŠ ๅๅผ•ๅท,realname

# ๆŸฅ
select * from users; # ๆŸฅ่ฏขusers่กจ็š„ๆ‰€ๆœ‰ๅ†…ๅฎน
select id,username from users; # ๆŸฅ่ฏขusers่กจ็š„id,username

## ๆกไปถๆŸฅ่ฏข ๅŒๆ—ถๆปก่ถณ
select * from users where username='zhangsan' and `password`='123' 
## ๆกไปถๆŸฅ่ฏข ๅนถ้›†ๆŸฅ่ฏข ๆปก่ถณๅ…ถไธ€็š„ๅฐฑๆ˜พ็คบ
select * from users where username='zhangsan' or `password`='123'

## ๆจก็ณŠๆŸฅ่ฏข
select * from users where username like '%zhang%'; 

## ๆŽ’ๅบๆŸฅ่ฏข(ๆญฃๅบ)๏ผŒๆจก็ณŠๆŸฅ่ฏขๆœ‰1็š„็ป“ๆžœๆŒ‰็…งidๆŽ’ๅบ
select * from users where `password` like '%1%' order by id ;

## ๆŽ’ๅบๆŸฅ่ฏข(ๅ€’ๅบ)๏ผŒๆจก็ณŠๆŸฅ่ฏขๆœ‰1็š„็ป“ๆžœๆŒ‰็…งidๆŽ’ๅบ 
select * from users where `password` like '%1%' order by id desc; 

# ๆ›ดๆ–ฐ
update users set relname='ๆŽๅ››2' where username='lisi'
## ๅฆ‚ๆžœ่งฆๅ‘MySQLๅฎ‰ๅ…จๆœบๅˆถ๏ผŒๅฏไปฅๅ…ณ้—ญ,ๅ†ๆ‰ง่กŒๆ›ดๆ–ฐ่ฏญๅฅ
SET SQL_SAFE_UPDATES=0;

# ๅˆ ้™ค(ไธ€ๅฎšๅธฆwhereๆกไปถ)
delete from users where username="lisi";

## ้€š่ฟ‡ๅญ—ๆฎตๆฅ่กจ็คบๅˆ ้™ค๏ผŒ่€Œไธๆ˜ฏ็œŸๅฎždeleteๅˆ ้™ค
select * from users where state='1';
-- select * from users where state<>'0';(ๅฆไธ€็งๅ†™ๆณ• <>0 ่กจ็คบไธ็ญ‰ไบŽ0)
update users set state='0' where username='lisi' # ่ฎพ็ฝฎstate=0่กจ็คบๅˆ ้™ค(่ฝฏๅˆ ้™ค)

# ๆŸฅ็œ‹mysql็‰ˆๆœฌๅท
select version();

Nodejs่ฟžๆŽฅMySQL

API ่ฟžๆŽฅ mysql---test04

npm i mysql

const mysql = require('mysql');

//ๅˆ›ๅปบๆ•ฐๆฎๅบ“ๅฏน่ฑก
const connection = mysql.createConnection({
    host:'localhost',
    port:'3306',
    user:'xxx',
    password:'xxx',
    database:'myblog'
});

//ๅผ€ๅง‹้“พๆŽฅ
connection.connect();

//ๆ‰ง่กŒsql่ฏญๅฅ
connection.query(sql่ฏญๅฅ,(err,results)=>{
    if (err) throw err;
    console.log(results)
})

//ๅ…ณ้—ญ
connection.end()
## ้‡ๅˆฐ็š„้—ฎ้ข˜ -- ๅฎ‰่ฃ…ๅฎŒๆ— ๆณ•่ฟžๆŽฅmysql๏ผŒ้”™่ฏฏไฟกๆฏ
Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

## ่งฃๅ†ณๆ–นๆณ•
mysql -u root -p #็™ปๅฝ•mysql
Enter password: ่พ“ๅ…ฅไฝ ๅฝ“ๅ‰็š„mysqlๅฏ†็ 

mysql> ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_new_password';
mysql> FLUSH PRIVILEGES;
mysql> quit

้‡ๆ–ฐ่ฟžๆŽฅnode--node mysql.js
[ RowDataPacket { id: 1, username: 'zhangsan', password: '123', realname: 'ๅผ ไธ‰' },
  RowDataPacket { id: 2, username: 'lisi', password: '456', realname: 'ๆŽๅ››2' } ]

้กน็›ฎ้‡Œไฝฟ็”จmysqlๅˆ›ๅปบAPIๆŽฅๅฃ----ๆ•ฐๆฎ่Žทๅ–ๅ’Œ่ฟ”ๅ›žๆ“ไฝœ

# ๅˆ›ๅปบdb/conf.js ๅˆฉ็”จprocess.env.NODE_ENVๆฅๅŒบๅˆ†็บฟไธŠๅ’Œๆœฌๅœฐ็‰ˆๆœฌ็š„ๆ•ฐๆฎๅบ“้…็ฝฎ

const env = process.env.NODE_ENV //็Žฏๅขƒๅ‚ๆ•ฐ

//้…็ฝฎ
let MYSQL_CONF

if ( env === 'dev' ) {
  MYSQL_CONF = {
    host:"localhost",
    port:"3306",
    user:"root",
    password:"xxx",
    database:"myBlogs"
  }
}

if ( env === 'production' ) {
  MYSQL_CONF = {
    host:"xxx.xxx.xxx.xxx",
    port:"3306",
    user:"root",
    password:"xxx",
    database:"myBlogs"
  }
}
module.exports = {
  MYSQL_CONF
}
# ๅˆ›ๅปบdb/mysql.js  ๅฏๅŠจnodeๅ’Œmysqlๅปบ็ซ‹่ฟžๆŽฅ ๅฐ่ฃ…็ปŸไธ€ๆ‰ง่กŒSQL็š„ๅ‡ฝๆ•ฐdoSQL
const mysql = require('mysql');
const { MYSQL_CONF }  = require('./conf');

const connection  = mysql.createConnection(MYSQL_CONF);

connection.connect();

//็ปŸไธ€ๆ‰ง่กŒsqlๅ‡ฝๆ•ฐ
function doSQL(sql){
  const promise = new Promise((resolve,reject)=>{
    connection.query(sql,(err,res)=>{
      if(err) reject(err); 
      resolve(res);
    })
  });
  return promise;
}
module.exports = {
    doSQL
}
# controllers/blogs.js ไฝฟ็”จSQL็ญ‰ๆ•ฐๆฎๅบ“ๆ“ไฝœ๏ผŒๅฏนๅ‡ๆ•ฐๆฎ่ฟ›่กŒๆ›ฟๆข --- ๅšๅฎขๅˆ—่กจ
const { doSQL } = require('../db/mysql');

/**
 * ่Žทๅ–ๅšๅฎขๅˆ—่กจๆ•ฐๆฎ GET
 * http://localhost:8000/api/blog/list
 * http://localhost:8000/api/blog/list?author=zhangsan
 * http://localhost:8000/api/blog/list?author=zhangsan&keyword=A
 */
const getList = (author,keyword) => {
    console.log(author,keyword);
    let sql = `select * from blogs where 1=1`
    if(author){
      sql += ` and author='${author}'`
    }
    if(keyword){
      sql += ` and title like '%${keyword}%'` //ๆณจๆ„and ๅ‰้ข็š„็ฉบๆ ผ
    }
    sql += ` order by 'createtime' desc;` //ๆณจๆ„order ๅ‰้ข็š„็ฉบๆ ผ
    //่ฟ”ๅ›žpromise
    return doSQL(sql);
}

/**
 * ๆ นๆฎid่Žทๅ–ๅ•ไธชๅšๅฎข่ฏฆๆƒ… GET
 * http://localhost:8000/api/blog/detail?id=1
 * http://localhost:8000/api/blog/detail?id=2
 */
const getDetail = (id) => {
  let sql = `select * from blogs where id=${id}`;
  return doSQL(sql);
}
/**
 * ๅˆ›ๅปบๆ–ฐ็š„ๅšๅฎขๅ†…ๅฎน POST
 * http://localhost:8000/api/blog/new
 * body ๅ†…ๅฎน
  {
	  "title":"ๅšๅฎขxx",
	  "content":"ๅ†…ๅฎนxx"
  } 
 */
const newBlog = (blogData = {}) => {
  const { title,content,author} = blogData;
  let createtime = Date.now();
  let sql = `insert into blogs (title,content,createtime,author) values ('${title}','${content}',${createtime},'${author}');` //ๆณจๆ„ๆ‰ง่กŒ้กบๅบ

  return doSQL(sql).then(insertData=>{
    console.log('insertData==>',insertData);
    /*OkPacket {
      fieldCount: 0,
      affectedRows: 1,
      insertId: 3,
      serverStatus: 2,
      warningCount: 0,
      message: '',
      protocol41: true,
      changedRows: 0 }*/
    return {
      id:insertData.insertId //้€š่ฟ‡insertIdๆฅๅˆคๆ–ญๆ˜ฏๅฆๅŠ ่ฝฝๆˆๅŠŸ
    }
  });
}
/**
 * ๅˆ›ๅปบๆ–ฐ็š„ๅšๅฎขๅ†…ๅฎน POST
 * http://localhost:8000/api/blog/update?id=3
 * body ๅ†…ๅฎน
  {
	  "title":"ๅšๅฎขxxxx",
	  "content":"ๅ†…ๅฎนxxxxx"
  } 
 */
const updateBlog = (id,blogData = {}) => {
    // id ่ฆๆ›ดๆ–ฐ็š„ๅšๅฎขid
    // blogData ๅšๅฎขๅฏน่ฑก ๅŒ…ๅซtitle contentๅฏน่ฑก
    console.log('update blog',id,blogData);
    const { title , content } = blogData;
    let sql = `update blogs set title='${title}', content='${content}' where id=${id};` //ๆณจๆ„ ,็ฉบๆ ผ content='${content}'
    return doSQL(sql).then(updateRes=>{
      if(updateRes.affectedRows > 0){ //ๆ นๆฎaffectedRows>0ๆฅๅˆคๆ–ญๆ˜ฏๅฆๆ›ดๆ–ฐๆˆๅŠŸ
        return true;
      }
      return false;
    })
}
/**
 * ๅˆ›ๅปบๆ–ฐ็š„ๅšๅฎขๅ†…ๅฎน POST
 * http://localhost:8000/api/blog/del?id=3
 */
const delBlog = (id,author) => {
  //id ่ฆๅˆ ้™ค็š„ๅšๅฎขid
  let sql = `delete from blogs where id='${id}' and author='${author}';` //ๅฎ‰ๅ…จๆœบๅˆถ๏ผŒไฟ่ฏไฝœ่€…ไธ€่‡ด
  return doSQL(sql).then(updateRes=>{
    if(updateRes.affectedRows > 0){ //ๆ นๆฎaffectedRows>0ๆฅๅˆคๆ–ญๆ˜ฏๅฆๅˆ ้™คๆˆๅŠŸ
      return true;
    }
    return false;
  })
}
module.exports = {
  getList,
  getDetail,
  newBlog,
  updateBlog,
  delBlog
}
# controllers/user.js ไฝฟ็”จSQL็ญ‰ๆ•ฐๆฎๅบ“ๆ“ไฝœ๏ผŒๅฏนๅ‡ๆ•ฐๆฎ่ฟ›่กŒๆ›ฟๆข --- ็”จๆˆทๅˆ—่กจ
const { doSQL } = require('../db/mysql');
/**
 * ็”จๆˆท็™ปๅฝ•ๆณจๅ†Œ
 * http://localhost:8000/api/user/login
 * 
  {
    "username":"lisi",
    "password":"45655"
  }
 */
const loginCheck = (username,password) => {
  let sql = `select username,realname from users where username='${username}' and password='${password}';`

  return doSQL(sql).then(usersArr => {
      return usersArr[0] || {}
  })
}
module.exports = {
  loginCheck
}
# routers/blogs ๅฏนๆ•ฐๆฎ่ฟ›่กŒ่ทฏ็”ฑ่ฟ”ๅ›žๅค„็† -- ๅšๅฎขๅˆ—่กจ
const {
  getList,
  getDetail,
  newBlog,
  updateBlog,
  delBlog
} = require('../controllers/blog')
const { SuccessModel,ErrorModel }  = require('../models')
const handleBlogRouter = (req,res) =>{
    const method = req.method;
    const path = req.path;
    const query = req.query;
    const id = query && query.id;
   

    //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/blog/list
    if( method==="GET" && path === "/api/blog/list"){
        const { author , keyword } = query;
        // if(author && keyword){
        //   // const resData = getList(author,keyword);
        //   // return new SuccessModel(resData);
        //   return getList(author,keyword).then(resData=>{
        //     return new SuccessModel(resData);
        //   })
        // }else {
        //   return new ErrorModel('่Žทๅ–ๅšๅฎขๅˆ—่กจๅคฑ่ดฅ๏ผŒ่ฏทไผ ๆญฃ็กฎ็š„ๅ‚ๆ•ฐ author & keyword');
        // }
        return getList(author,keyword).then(resData=>{
          return new SuccessModel(resData);
        })
        
    }
    //่Žทๅ–ไธ€็ฏ‡ๅšๅฎข็š„ๅ†…ๅฎน  /api/blog/detail
    if( method==="GET" && path === "/api/blog/detail"){
        if(id){
          return getDetail(id).then(resData=>{
            return new SuccessModel(resData);
          })
        }
    }
    //ๆ–ฐๅขžไธ€็ฏ‡ๅšๅฎข   /api/blog/new 
    if( method==="POST" && path === "/api/blog/new"){
        req.body.author = "zhangsan" ; //ๅ‡ๆ•ฐๆฎ๏ผŒTODO๏ผš็™ปๅฝ•ๆณจๅ†Œ
        return newBlog(req.body).then(resData=>{
          return new SuccessModel(resData);
        });
    }
    //ๆ›ดๆ–ฐไธ€็ฏ‡ๅšๅฎข   /api/blog/update  
    if( method==="POST" && path === "/api/blog/update"){
       return updateBlog(id,req.body).then(resData=>{
          if(resData){
            return new SuccessModel('ๆ›ดๆ–ฐๅšๅฎขๆˆๅŠŸ');
          }else {
            return new ErrorModel('ๆ›ดๆ–ฐๅšๅฎขๅคฑ่ดฅ')
          }
       });
    }
    //ๅˆ ้™คไธ€็ฏ‡ๅšๅฎข   /api/blog/del   
    if( method==="POST" && path === "/api/blog/del"){
      req.body.author = "zhangsan" ; //ๅ‡ๆ•ฐๆฎ๏ผŒTODO๏ผš็™ปๅฝ•ๆณจๅ†Œ
      return delBlog(id,req.body.author).then(resData=>{
        if(resData){
          return new SuccessModel('ๅˆ ้™คๅšๅฎขๆˆๅŠŸ');
        }else{
          return new ErrorModel('ๅˆ ้™คๅšๅฎขๅคฑ่ดฅ');
        }
      });
      
    }
}
module.exports = handleBlogRouter;
# routers/users ๅฏนๆ•ฐๆฎ่ฟ›่กŒ่ทฏ็”ฑ่ฟ”ๅ›žๅค„็† -- ็”จๆˆทๅˆ—่กจ
const { loginCheck } = require('../controllers/user');
const { SuccessModel,ErrorModel }  = require('../models')
const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.path;

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="POST" && path === "/api/user/login"){
     const { username,password } = req.body;
     return loginCheck(username,password).then(loginRes => {
      if(loginRes.username){
        return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
       }
       return new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!');
     });
  }
  
}
module.exports = handleUserRouter;
# app.js ๅฏน็ป“ๆžœ่ฟ›่กŒๅ‰็ซฏ่ฟ”ๅ›ž
const queryString = require('querystring');
const handleBlogRouter= require('./routers/blog');
const handleUserRouter = require('./routers/user');

//่งฃๆžpost data๏ผŒ่ฟ”ๅ›žpromiseๅฏน่ฑก
const getPostData = (req) => {
    const promise = new Promise((resolve,reject) => {
          if(req.method === "POST" && req.headers['content-type'] === 'application/json'){
            let postData = "";
            req.on('data',chunk => postData += chunk.toString());
            req.on("end",()=>{
              if(postData){
                resolve(JSON.parse(postData));
              }else{
                resolve({});
                return;
              }
            })
          }else{
            resolve({});
            return;
          }
    });
    return promise;
}

const serverHandle = (req,res) => {
    //่ฎพ็ฝฎ่ฟ”ๅ›ž็š„JSON
    res.setHeader('Content-type','application/json');
    //่Žทๅ–path
    const url = req.url;
    req.path = url.split('?')[0];
    req.query = queryString.parse(url.split('?')[1])

    //่งฃๆžpostๆ•ฐๆฎ
    getPostData(req).then(postData => {
        req.body = postData;
        //ๅค„็†ๅšๅฎข็š„่ทฏ็”ฑ
        // const blogData = handleBlogRouter(req,res);
        // if(blogData){
        //   res.end(JSON.stringify(blogData));
        // }
        const blogRes = handleBlogRouter(req,res);
        if(blogRes){
          blogRes.then(blogData=>{
            res.end(JSON.stringify(blogData));
          });
          return;
        }
        
        //ๅค„็†็”จๆˆท็™ปๅฝ•็š„่ทฏ็”ฑ
        // const userData = handleUserRouter(req,res);
        // if(userData){
        //   res.end(JSON.stringify(userData));
        // }
        const userRes = handleUserRouter(req,res);
        if(userRes){
          userRes.then(userData=>{
            res.end(JSON.stringify(userData));
          });
          return;
        }
    })
    
    
}

module.exports = serverHandle;

็™ปๅฝ•--- ๆ ธๅฟƒ:็™ปๅฝ•ๆ ก้ชŒ & ็™ปๅฝ•ไฟกๆฏๅญ˜ๅ‚จ

cookieๅ’Œsession

cookie

1.ไป€ไนˆๆ˜ฏcookie

  • ๅญ˜ๅ‚จๅœจๆต่งˆๅ™จ็š„ไธ€ๆฎตๅญ—็ฌฆไธฒ๏ผˆๆœ€ๅคง5k๏ผ‰
  • ่ทจๅŸŸไธๅ…ฑไบซ
  • ๆ ผๅผๅฆ‚๏ผšk1=v1;k2=v2;k3=v3; ๅฏๅญ˜ๅ‚จ็ป“ๆž„ๅŒ–ๆ•ฐๆฎ
  • ๆฏๆฌกๅ‘้€http่ฏทๆฑ‚๏ผŒไผšๅฐ†่ฏทๆฑ‚ๅŸŸ็š„cookieไธ€่ตทๅ‘้€็ป™server
  • serverๅฏไปฅไฟฎๆ”นcookieๅนถ่ฟ”ๅ›ž็ป™ๆต่งˆๅ™จ
  • ๆต่งˆๅ™จไธญไนŸๅฏ้€š่ฟ‡jsไฟฎๆ”นcookie(้™ๅˆถ)

2.jsๆ“ไฝœcookie๏ผŒๆต่งˆๅ™จไธญๆŸฅ็œ‹cookie

  • ๅฎขๆˆท็ซฏๆŸฅ็œ‹cookieไธ‰็งๆ–นๅผ
    • ChromeๆŽงๅˆถๅฐ---> Network--->่ฏทๆฑ‚ไธญ็š„Request Header
    • ChromeๆŽงๅˆถๅฐ---> Application --> Storage -->Cookies
    • ChromeๆŽงๅˆถๅฐ---> Console --->่พ“ๅ…ฅ 'document.cookie'(jsๆŸฅ็œ‹)

- jsไฟฎๆ”นcookie(ๆœ‰้™ๅˆถ) - document.cookie='k1=100;' - document.cookie='k2=100;' - cookieไผš็ดฏๅŠ --> ็ป“ๆžœ: document.cookie --> "k1=100;k2=100;"

3.server็ซฏๆ“ไฝœcookie๏ผŒๅฎž็Žฐ็™ปๅฝ•้ชŒ่ฏ

  • ๆŸฅ็œ‹cookie -- req.headers.cookie
  • ไฟฎๆ”นcookie -- res.setHeader('Set-Cookie',key1=v1;key2=v2;path=/)
  • ๆจกๆ‹Ÿๅฎž็Žฐ็™ปๅฝ•้ชŒ่ฏ ๅŽŸ็†๏ผš้€š่ฟ‡get่ฏทๆฑ‚่พ“ๅ…ฅ่ดฆๅทๅ’Œๅฏ†็ ๏ผŒ็ฌฌไธ€ๆฌก็™ป้™†ๅฎŒ๏ผŒserver็ซฏๅœจๅฎขๆˆท็ซฏ็งไธ€ไธชcookie๏ผŒๅฆ‚ๆžœไธ‹ๆฌกๅ†็™ปๅฝ•๏ผŒRequest Header้‡ŒไผšๆบๅธฆไธŠๆฌก็š„cookie
    //ๅœจserverHandleๅ‡ฝๆ•ฐ้‡Œ ่งฃๆžcookie
    req.cookie = {}; //ๆŒ‚่ฝฝๅœจreqไธŠ
    const cookieStr = req.headers.cookie || ''; // k1=v1;k2=v2;
    cookieStr.split(';').forEach(item=>{
        let key = item.split('=')[0] || "";
        let value = item.split('=')[1] || "";
        req.cookie[key] = value;
    })
    console.log('req.cookie',req.cookie);
const { loginCheck } = require('../controllers/user');
const { SuccessModel,ErrorModel }  = require('../models')
const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.path;

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="GET" && path === "/api/user/login"){ //่ฟ™้‡Œไฟฎๆ”นไธบGETๆฅๆจกๆ‹Ÿ
    //  const { username,password } = req.body;
     const { username,password } = req.query;
     return loginCheck(username,password).then(loginRes => {
      if(loginRes.username){
        res.setHeader('Set-Cookie',`username=${loginRes.username};path=/;`)
        return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
       }
       return new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!');
     });
  }
}
module.exports = handleUserRouter;
# test URL: http://localhost:8000/api/user/login?username=zhangsan&password=123
ไผšๅœจๆต่งˆๅ™จ็งไธ€ไธชcookie

Response Header:
Connection: keep-alive
Content-Length: 37
Content-type: application/json
Date: Tue, 30 Jul 2019 14:11:56 GMT
Set-Cookie: username=zhangsan;path=/; # ่ฟ™ไธชๆ˜ฏๆœๅŠก็ซฏ็งไธŠ็š„

# ๅ†ๆฌก่ฏทๆฑ‚
Request Header:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Cookie: username=zhangsan  #่ฟ™้‡ŒไผšๆบๅธฆไธŠๆฌก็งไธŠ็š„็š„cookie
Host: localhost:8000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36

4.cookieๅฎ‰ๅ…จๆ€ง 4.1 httpOnly ๅœบๆ™ฏ๏ผšๅฏนไบŽ็™ปๅฝ•็š„lisi๏ผŒๅฆ‚ๆžœ้€š่ฟ‡ๅ‰็ซฏไฟฎๆ”นdocument.cookie="zhangsan"๏ผŒไผšๅฏผ่‡ดzhangsan็š„ๆ•ฐๆฎๆณ„ๆผ๏ผŒไธบไบ†้˜ฒๆญข่ฟ™็งๆƒ…ๅ†ต๏ผŒๆœๅŠก็ซฏ้œ€่ฆ่ฟ›่กŒๅฎ‰ๅ…จ้™ๅˆถ๏ผŒ้˜ฒๆญขๅ‰็ซฏไฟฎๆ”นcookie

# ่ฎพ็ฝฎhttpOnly
 res.setHeader('Set-Cookie',`username=${loginRes.username};path=/; httpOnly`);

4.2 ่ฎพ็ฝฎcookie่ฟ‡ๆœŸๆ—ถ้—ด ๅœบๆ™ฏ:ๅฏนไบŽ้•ฟๆ—ถ้—ด็™ปๅฝ•็š„็Šถๆ€๏ผŒ้œ€่ฆๅฎšๆ—ถ่ฎฉ็”จๆˆท็™ปๅฝ•๏ผŒ้˜ฒๆญขไป–ไบบ่Žทๅ–็™ปๅฝ•ๅŽ็š„็”จๆˆทไฟกๆฏ

//่ฎพ็ฝฎcookie่ฟ‡ๆœŸๆ—ถ้—ด GMTๆ ผๅผ
const setCookieExpires = () => {
    const date = new Date();
    date.setTime(date.getTime() + (24*60*60*1000));
    return date.toGMTString();
}

res.setHeader('Set-Cookie',`username=${loginRes.username};path=/; httpOnly; expires=${setCookieExpires()}`);
cookieๆ€ป็ป“
  • ็Ÿฅ้“cookie็š„ๅฎšไน‰ๅ’Œ็‰น็‚น
  • ๅ‰ๅŽ็ซฏๅฆ‚ไฝ•ๆŸฅ็œ‹ๅ’Œไฟฎๆ”นcookie
  • ๅฆ‚ไฝ•ไฝฟ็”จcookieๅฎž็Žฐ็™ปๅฝ•้ชŒ่ฏ

session

ไธบไป€ไนˆไฝฟ็”จsession --- cookieไผšๆšด้œฒusername๏ผŒๅพˆๅฑ้™ฉ

  • ่งฃๅ†ณๆ–นๆกˆ๏ผšcookieไธญๅญ˜ๅ‚จuserid๏ผŒserver็ซฏๅฏนๅบ”username๏ผŒ
  • ๅŽŸ็† session๏ผŒๅณserver็ซฏๅญ˜ๅ‚จ็”จๆˆทไฟกๆฏ๏ผŒserver็ซฏ็ป™ๅฎขๆˆท็ซฏcookie็งไธ€ไธชๅชๆœ‰server็ซฏ่ฎค่ฏ†็š„userid๏ผŒๆ นๆฎ่ฟ™ไธชๅŽป้ชŒ่ฏusernameๆ˜ฏๅฆๆ˜ฏไธ€ไธชไบบ
ๅˆฉ็”จๅ˜้‡ๅญ˜ๅ‚จsessionๆ•ฐๆฎ๏ผŒๅˆฉ็”จcookieๆฅๅฎž็Žฐsession--demo
# ๆ ธๅฟƒๅฎž็Žฐไปฃ็  ไปฃ็ ไธๅˆ†ๆ–‡ไปถๅ’Œๆ‰ง่กŒ้กบๅบ
const SESSION_DATA = {}; //ๅญ˜ๅ‚จsession

//ๆ นๆฎcookie่งฃๆžsession
  let userId = req.cookie.userid;
  let needSetCookie = false;
  if(userId){ //ๅˆคๆ–ญๆ˜ฏๅฆๅทฒ็ปๆœ‰userId,ๆฅๅ†ณๅฎšๆ˜ฏๅฆๆ˜ฏๅŒไธ€ไธช็”จๆˆท ๆˆ–ๆ˜ฏ ๅœจๅ‰็ซฏ็งไธ€ไธช่‡ชๅทฑ่ƒฝ่ฏ†ๅˆซ็š„userid
    if(!SESSION_DATA[userId]){ //่กจ็คบๆœ‰userid๏ผŒไฝ†ๆ˜ฏๆฒกๆœ‰ๆ‰พๅˆฐๅฏนๅบ”็š„username็ญ‰ๆ•ฐๆฎ,ๆธ…็ฉบๅญ˜ๅ‚จๅฝ“ๅ‰userid็”จๆˆท็š„ๅฏน่ฑก
      SESSION_DATA[userId] = {};
    } 
  } else { //ๅœจๅ‰็ซฏ็งไธ€ไธช่‡ชๅทฑ่ƒฝ่ฏ†ๅˆซ็š„userid
    needSetCookie = true;
    userId = `${Date.now()}_${Math.random()}`;
    SESSION_DATA[userId] = {};
  }
  /** 
   * ๅญ˜ๅ‚จๅฝ“ๅ‰็”จๆˆท็š„userId  ๆ•ฐๆฎ็ป“ๆž„ๆ˜ฏ 
   * SESSION_DATA = {
   *    1:{username:xxx,relaname:xxx},
   *    2:{username:xxx,relaname:xxx},
   *    '1565508588565_0.41190501274115565': { username: 'zhangsan', realname: 'ๅผ ไธ‰' } 
   * }
  */
  req.session = SESSION_DATA[userId]; 
  console.log('SESSION_DATA',SESSION_DATA);
  
  //ๆ นๆฎๅ˜้‡้‡Œ็š„useridๆฅๅˆคๆ–ญๆ˜ฏๅฆๅœจๅ‰็ซฏ็งcookie
  if(needSetCookie){
      res.setHeader('Set-Cookie',`userid=${userId};path=/; httpOnly; expires=${setCookieExpires()}`);
  }
  //่ฎพ็ฝฎsession๏ผŒๆœ็ดขๆ•ฐๆฎๅบ“๏ผŒๅฐ†็œŸๅฎž็š„็”จๆˆทๅๅ’Œuseridๅฏนๅบ”
  if(loginRes.username){
        // res.setHeader('Set-Cookie',`username=${loginRes.username};path=/; httpOnly; expires=${setCookieExpires()}`);
        req.session.username = loginRes.username;
        req.session.realname = loginRes.realname;
        console.log('req.session is', req.session);
        return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
  }
 # app.jsๅฎŒๆ•ดไปฃ็ 
 const queryString = require('querystring');
const handleBlogRouter= require('./routers/blog');
const handleUserRouter = require('./routers/user');

const SESSION_DATA = {}; //ๅญ˜ๅ‚จsession
//่ฎพ็ฝฎcookie่ฟ‡ๆœŸๆ—ถ้—ด GMTๆ ผๅผ
const setCookieExpires = () => {
  const date = new Date();
  date.setTime(date.getTime() + (24*60*60*1000));
  return date.toGMTString();
}

//่งฃๆžpost data๏ผŒ่ฟ”ๅ›žpromiseๅฏน่ฑก
const getPostData = (req) => {
    const promise = new Promise((resolve,reject) => {
          if(req.method === "POST" && req.headers['content-type'] === 'application/json'){
            let postData = "";
            req.on('data',chunk => postData += chunk.toString());
            req.on("end",()=>{
              if(postData){
                resolve(JSON.parse(postData));
              }else{
                resolve({});
                return;
              }
            })
          }else{
            resolve({});
            return;
          }
    });
    return promise;
}

const serverHandle = (req,res) => {
    //่ฎพ็ฝฎ่ฟ”ๅ›ž็š„JSON
    res.setHeader('Content-type','application/json');
    //่Žทๅ–path
    const url = req.url;
    req.path = url.split('?')[0];

    //่งฃๆžquery
    req.query = queryString.parse(url.split('?')[1])

    //่งฃๆžcookie
    req.cookie = {};
    const cookieStr = req.headers.cookie || ''; // k1=v1;k2=v2;
    cookieStr.split(';').forEach(item=>{
        if(!item) return;

        const arr = item.split('=');
        const key = arr[0].trim() || "";
        const value = arr[1].trim() || "";
        req.cookie[key] = value;
    })
    console.log('req.cookie',req.cookie);

    //ๆ นๆฎcookie่งฃๆžsession
    let userId = req.cookie.userid;
    let needSetCookie = false;
    if(userId){ //ๅˆคๆ–ญๆ˜ฏๅฆๅทฒ็ปๆœ‰userId,ๆฅๅ†ณๅฎšๆ˜ฏๅฆๆ˜ฏๅŒไธ€ไธช็”จๆˆท ๆˆ–ๆ˜ฏ ๅœจๅ‰็ซฏ็งไธ€ไธช่‡ชๅทฑ่ƒฝ่ฏ†ๅˆซ็š„userid
      if(!SESSION_DATA[userId]){ //่กจ็คบๆœ‰userid๏ผŒไฝ†ๆ˜ฏๆฒกๆœ‰ๆ‰พๅˆฐๅฏนๅบ”็š„username็ญ‰ๆ•ฐๆฎ,ๆธ…็ฉบๅญ˜ๅ‚จๅฝ“ๅ‰userid็”จๆˆท็š„ๅฏน่ฑก
        SESSION_DATA[userId] = {};
      } 
    } else { //ๅœจๅ‰็ซฏ็งไธ€ไธช่‡ชๅทฑ่ƒฝ่ฏ†ๅˆซ็š„userid
      needSetCookie = true;
      userId = `${Date.now()}_${Math.random()}`;
      SESSION_DATA[userId] = {};
    }
    /** 
     * ๅญ˜ๅ‚จๅฝ“ๅ‰็”จๆˆท็š„userId  ๆ•ฐๆฎ็ป“ๆž„ๆ˜ฏ 
     * SESSION_DATA = {
     *    1:{username:xxx,relaname:xxx},
     *    2:{username:xxx,relaname:xxx},
     *    '1565508588565_0.41190501274115565': { username: 'zhangsan', realname: 'ๅผ ไธ‰' } 
     * }
    */
    req.session = SESSION_DATA[userId]; 
    console.log('SESSION_DATA',SESSION_DATA);

    //่งฃๆžpostๆ•ฐๆฎ
    getPostData(req).then(postData => {
        req.body = postData;
        //ๅค„็†ๅšๅฎข็š„่ทฏ็”ฑ
        // const blogData = handleBlogRouter(req,res);
        // if(blogData){
        //   res.end(JSON.stringify(blogData));
        // }
        const blogRes = handleBlogRouter(req,res);
        if(blogRes){
          blogRes.then(blogData=>{
            if(needSetCookie){
              res.setHeader('Set-Cookie',`userid=${userId};path=/; httpOnly; expires=${setCookieExpires()}`);
            }
            res.end(JSON.stringify(blogData));
          });
          return;
        }
        
        //ๅค„็†็”จๆˆท็™ปๅฝ•็š„่ทฏ็”ฑ
        // const userData = handleUserRouter(req,res);
        // if(userData){
        //   res.end(JSON.stringify(userData));
        // }
        const userRes = handleUserRouter(req,res);
        if(userRes){
          userRes.then(userData=>{
            if(needSetCookie){
              res.setHeader('Set-Cookie',`userid=${userId};path=/; httpOnly; expires=${setCookieExpires()}`);
            }
            res.end(JSON.stringify(userData));
          });
          return;
        }
    })
    
    
}

module.exports = serverHandle;
# user.jsๅฎŒๆ•ดไปฃ็ 
const { loginCheck } = require('../controllers/user');
const { SuccessModel,ErrorModel }  = require('../models');

//่ฎพ็ฝฎcookie่ฟ‡ๆœŸๆ—ถ้—ด GMTๆ ผๅผ
const setCookieExpires = () => {
    const date = new Date();
    date.setTime(date.getTime() + (24*60*60*1000));
    return date.toGMTString();
}

const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.path;

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="GET" && path === "/api/user/login"){
    //  const { username,password } = req.body;
     const { username,password } = req.query;
     return loginCheck(username,password).then(loginRes => {
      if(loginRes.username){
        // res.setHeader('Set-Cookie',`username=${loginRes.username};path=/; httpOnly; expires=${setCookieExpires()}`);
        req.session.username = loginRes.username;
        req.session.realname = loginRes.realname;
        console.log('req.session is', req.session);
        return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
       }
       return new ErrorModel('===>็™ปๅฝ•ๅคฑ่ดฅ!');
     });
  }
  //ๆต‹่ฏ•๏ผš้€š่ฟ‡sessionๆฅ็™ปๅฝ•้ชŒ่ฏ
  if( method==="GET" && path === "/api/user/login-test"){
    console.log('login-test,req.session==>',req.session);
    console.log('login-test,req.cookie==>',req.cookie);
    if(req.session.username){
        return Promise.resolve(
          new SuccessModel({
            session:req.session
          })
        );
     }
     return Promise.resolve(new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ===>!'));
  }
  
}
module.exports = handleUserRouter;

sessionไฝฟ็”จjsๅ˜้‡ๆฅๅญ˜ๅ‚จๅธฆๆฅ็š„้—ฎ้ข˜ --- ่งฃๅ†ณๆ–นๆกˆ๏ผšredis

็›ฎๅ‰session ็›ดๆŽฅๆ˜ฏjsๅ˜้‡๏ผŒๆ”พๅœจnodejs่ฟ›็จ‹ๅ†…ๅญ˜ไธญ(Node่ฟ›็จ‹ๆœ‰้™)

  • ็ฌฌไธ€๏ผŒ่ฟ›็จ‹ๅ†…ๅญ˜ๆœ‰้™๏ผŒ่ฎฟ้—ฎ้‡่ฟ‡ๅคง๏ผŒๅ†…ๅญ˜ๆšดๅขžๆ€ŽไนˆๅŠž๏ผŸ(็”จๆˆท่ฎฟ้—ฎๅฆ‚ๆžœๅขžๅคš)
  • ็ฌฌไบŒ๏ผŒๆญฃๅผ็บฟไธŠ่ฟ่กŒๆ˜ฏๅคš่ฟ›็จ‹็š„๏ผŒ่ฟ›็จ‹ไน‹้—ดๅ†…ๅญ˜ๆ— ๆณ•ๅ…ฑไบซ(ๅฝ“ๅ‰็”จๆˆท1็š„ๆ•ฐๆฎๅญ˜ๅœจ่ฟ›็จ‹1๏ผŒไฝ†ๆ˜ฏๅฆ‚ๆžœไธ‹ๆฌก่ฎฟ้—ฎ็”จๆˆท1,่ฟ›ๅˆฐ้‡Œ่ฟ›็จ‹2๏ผŒ่ฟ›็จ‹2ไธๅญ˜ๅœจ็”จๆˆท1็š„ๆ•ฐๆฎ๏ผŒๅฐฑไผšๅฏผ่‡ด่ฟ›็จ‹2้‡ๅคๅˆ›ๅปบๆ•ฐๆฎ)

่งฃๅ†ณๆ–นๆกˆ--redis

  • web serverๆœ€ๅธธ็”จ็š„็ผ“ๅญ˜ๆ•ฐๆฎๅบ“๏ผŒๆ•ฐๆฎๅญ˜ๅ‚จๅœจๅ†…ๅญ˜ไธญ
  • ็›ธๆฏ”ไบŽmysql๏ผŒ่ฎฟ้—ฎ้€Ÿๅบฆๅฟซ(ๅ†…ๅญ˜ๅ’Œ็กฌ็›˜ๆ•ฐๆฎๅบ“ไธๆ˜ฏไธ€ไธชๆ•ฐ้‡็บง)
  • ไฝ†ๆˆๆœฌๆ›ด้ซ˜๏ผŒๅฏๅญ˜ๅ‚จ็š„ๆ•ฐๆฎ้‡ๆ›ดๅฐ(ๅ†…ๅญ˜็š„็กฌไผค)
  • ๅฐ†web serverๅ’Œredisๆ‹†ๅˆ†ๆˆไธคไธชๅ•็‹ฌ็š„ๆœๅŠก(ๅ…ณ้”ฎ!!!)
  • ๅŒๆ–น้ƒฝๆ˜ฏ็‹ฌ็ซ‹็š„๏ผŒ้ƒฝๆ˜ฏๅฏๆ‰ฉๅฑ•็š„(ไพ‹ๅฆ‚ ้ƒฝๆ‰ฉๅฑ•ๆˆ้›†็พค)
  • ๅŒ…ๆ‹ฌmysql๏ผŒไนŸๆ˜ฏไธ€ไธชๅ•็‹ฌ็š„ๆœๅŠก๏ผŒไนŸๅฏๆ‰ฉๅฑ•

ไธบไป€ไนˆsession้€‚็”จredis๏ผŸ

  • session่ฎฟ้—ฎ้ข‘็น๏ผŒๅฏนๆ€ง่ƒฝ่ฆๆฑ‚ๆž้ซ˜
  • sessionๅฏไธ่€ƒ่™‘ๆ–ญ็”ตไธขๅคฑๆ•ฐๆฎ็š„้—ฎ้ข˜
  • sessionๆ•ฐๆฎ้‡ไธไผšๅคชๅคง

ไธบไป€ไนˆ็ฝ‘็ซ™ๆ•ฐๆฎไธ้€‚ๅˆ็”จredis๏ผŸ

  • ๆ“ไฝœ้ข‘็އไธๆ˜ฏๅคช้ซ˜
  • ๆ–ญ็”ตไธ่ƒฝไธขๅคฑ๏ผŒๅฟ…้กปไฟ็•™
  • ๆ•ฐๆฎ้‡ๅคชๅคง๏ผŒๅ†…ๅญ˜ๆˆๆœฌๅคช้ซ˜
ๅฎ‰่ฃ…redis

windowsๅฎ‰่ฃ…redis
Macๅฎ‰่ฃ… brew install redis

# redisไฝฟ็”จ
redis-server #ๅฏๅŠจๆœๅŠก
redis-cli # ๆ–ฐๅปบ็ช—ๅฃ

set key1 value1 # ่ฎพ็ฝฎkey:value
get key1    # ่Žทๅ–key็š„ๅ€ผ
keys *      # ่Žทๅ–ๆ‰€ๆœ‰key
del key1    # ๅˆ ้™คๅฝ“ๅ‰key
Nodejs ๅฏๅŠจRedis -- test05

npm install redis --save

const redis = require('redis');

//ๅˆ›ๅปบๅฎขๆˆท็ซฏ
const redisClient = redis.createClient(6379,'127.0.0.1');
redisClient.on('error',err=>{
    console.log(err);
});

//test-่ฎพ็ฝฎๅ€ผ๏ผŒๅ–ๅ€ผ
redisClient.set('myname','zhangsan2',redis.print);
redisClient.get('myname',(err,val)=>{
    if(err){
      console.error(err);
      return;
    }
    console.log('val',val);
    redisClient.quit();
});

node index.js # ้€š่ฟ‡node่ฟžๆŽฅredis ่ฏปๅ†™ๆ“ไฝœ

Reply: OK
val zhangsan2

# redisๅฎขๆˆท็ซฏๆŸฅ็œ‹ๆ˜ฏๅฆ็”Ÿๆˆkey
redis-cli
127.0.0.1:6379> keys *
1) "myname"

ไฝฟ็”จredisๆ›ฟๆขsessionๅ˜้‡

##### db/conf.js #####
let REDIS_CONF;

if ( env === 'dev' ) {
  REDIS_CONF = {
    host:'127.0.0.1',
    port:6379
  }
}

if ( env === 'production' ) {
  REDIS_CONF = {
    host:'127.0.0.1',
    port:6379
  }
}
module.exports = {
  REDIS_CONF
}

##### db/redis.js ๅฐ่ฃ…get & set ๆ–นๆณ• #####
const redis = require('redis');
const { REDIS_CONF } = require('./conf');
const { port , host } = REDIS_CONF;

//ๅˆ›ๅปบๅฎขๆˆท็ซฏ
const redisClient = redis.createClient(port,host);

redisClient.on('error',err => {
    console.error(err);
});

//ๅฐ่ฃ… redis setๆ–นๆณ•
function redisSet(key,val){
    if(typeof val === 'object'){
        val = JSON.stringify(val);
    }
    redisClient.set(key,val,redis.print);
}
//ๅฐ่ฃ… redis getๆ–นๆณ•
function redisGet(key){
  const promise = new Promise((resolve,reject) =>{
    redisClient.get(key,(err,val) =>{
        if(err){
          reject(err);
          return;
        }
        if(val === null){
          resolve(null);
          return;
        }
        try {
          resolve(JSON.parse(val)); //try/catch ไธๆ˜ฏไธบไบ†ๆŠ“ๅผ‚ๅธธ,่€Œๆ˜ฏๅ…ผๅฎนๅฏน่ฑก็š„ๅ€ผ
        }catch(e){
          resolve(val);
        }
        
    });
  });
  return promise;
}
module.exports = {
  redisSet,
  redisGet
}

##### app.js #######
const { redisSet, redisGet } = require('./db/redis');
//ๅฐ†sessionๅญ˜ๅ‚จๅˆฐredisไธญ
  let userId = req.cookie.userid;
  let needSetCookie = false;
  if(!userId){
      needSetCookie = true;
      userId = `${Date.now()}_${Math.random()}`;
      redisSet(userId,{});
  }
  // ่Žทๅ–ๅฝ“ๅ‰useridๅฏนๅบ”็š„username๏ผŒrelaname
  req.sessionId = userId;
  redisGet(req.sessionId).then(sessionData => {
      if(sessionData == null){
        redisSet(req.sessionId,{});
        req.session = {};
      } else {
        req.session = sessionData;
      }
  });

##### routers/user.js #####
const { redisSet } = require('../db/redis');

req.session.username = loginRes.username;
req.session.realname = loginRes.realname;
redisSet(req.sessionId,req.session);

ๅฎŒๆˆblog็š„็™ปๅฝ•้ชŒ่ฏ

# router/blog.js
const {
  getList,
  getDetail,
  newBlog,
  updateBlog,
  delBlog
} = require('../controllers/blog');
const { SuccessModel,ErrorModel }  = require('../models');

// ๆ–ฐๅขž๏ผš็ปŸไธ€็™ปๅฝ•้ชŒ่ฏๅ‡ฝๆ•ฐ
const loginCheck = (req) => {
    if(!req.session.username){
        return Promise.resolve(
          new ErrorModel('ๅฐšๆœช็™ปๅฝ•')
        )
    }
}
//ๆ–ฐๅขž๏ผš้ชŒ่ฏๆ˜ฏๅฆ็™ปๅฝ•
const loginCheckResFunc = (req) => {
    const loginCheckRes = loginCheck(req);
    if(loginCheckRes){
      return loginCheckRes;
    }
}
const handleBlogRouter = (req,res) =>{
    const method = req.method;
    const path = req.path;
    const query = req.query;
    const id = query && query.id;
   

    //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/blog/list
    if( method==="GET" && path === "/api/blog/list"){
        const { author , keyword } = query;
        return getList(author,keyword).then(resData=>{
          return new SuccessModel(resData);
        })
        
    }
    //่Žทๅ–ไธ€็ฏ‡ๅšๅฎข็š„ๅ†…ๅฎน  /api/blog/detail
    if( method==="GET" && path === "/api/blog/detail"){
        if(id){
          return getDetail(id).then(resData=>{
            return new SuccessModel(resData);
          })
        }
    }
    //ๆ–ฐๅขžไธ€็ฏ‡ๅšๅฎข   /api/blog/new 
    if( method==="POST" && path === "/api/blog/new"){
        loginCheckResFunc(req); //ๆ–ฐๅขž
        req.body.author = req.session.username; //ๆ–ฐๅขž๏ผŒไธๅ†ๆ˜ฏๅ‡ๆ•ฐๆฎ
        return newBlog(req.body).then(resData=>{
          return new SuccessModel(resData);
        });
    }
    //ๆ›ดๆ–ฐไธ€็ฏ‡ๅšๅฎข   /api/blog/update  
    if( method==="POST" && path === "/api/blog/update"){
      loginCheckResFunc(req); //ๆ–ฐๅขž
       return updateBlog(id,req.body).then(resData=>{
          if(resData){
            return new SuccessModel('ๆ›ดๆ–ฐๅšๅฎขๆˆๅŠŸ');
          }else {
            return new ErrorModel('ๆ›ดๆ–ฐๅšๅฎขๅคฑ่ดฅ')
          }
       });
    }
    //ๅˆ ้™คไธ€็ฏ‡ๅšๅฎข   /api/blog/del   
    if( method==="POST" && path === "/api/blog/del"){
      loginCheckResFunc(req); //ๆ–ฐๅขž
      req.body.author = req.session.username; //ๆ–ฐๅขž
      return delBlog(id,req.body.author).then(resData=>{
        if(resData){
          return new SuccessModel('ๅˆ ้™คๅšๅฎขๆˆๅŠŸ');
        }else{
          return new ErrorModel('ๅˆ ้™คๅšๅฎขๅคฑ่ดฅ');
        }
      });
      
    }
}
module.exports = handleBlogRouter;
# routers/user.js
const { loginCheck } = require('../controllers/user');
const { SuccessModel,ErrorModel }  = require('../models');
const { redisSet } = require('../db/redis');

const handleUserRouter = (req,res) =>{
  const method = req.method;
  const path = req.path;

  //่Žทๅ–ๅšๅฎขๅˆ—่กจ  /api/user/login
  if( method==="POST" && path === "/api/user/login"){
     const { username,password } = req.body;
     return loginCheck(username,password).then(loginRes => {
      if(loginRes.username){
        req.session.username = loginRes.username;
        req.session.realname = loginRes.realname;
        redisSet(req.sessionId,req.session);
        return new SuccessModel('็™ป้™†ๆˆๅŠŸ!');
       }
       return new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!');
     });
  }
}
module.exports = handleUserRouter;

ๅผ€ๅ‘็™ปๅฝ•ๅŠŸ่ƒฝ๏ผŒๅ’Œๅ‰็ซฏ่”่ฐƒ๏ผˆngnixๅๅ‘ไปฃ็†๏ผ‰

  • ็™ปๅฝ•ๅŠŸ่ƒฝไพ่ต–cookie๏ผŒๅฟ…้กป็”จๆต่งˆๅ™จๆฅ่”่ฐƒ
  • cookie่ทจๅŸŸไธๅ…ฑไบซ๏ผŒๅ‰็ซฏๅ’Œserver็ซฏๅฟ…้กปๅŒๅŸŸ
  • ้œ€่ฆ็”จๅˆฐnginxๅšไปฃ็†๏ผŒ่ฎฉๅ‰ๅŽ็ซฏๅŒๅŸŸ

ๅ‡†ๅค‡ๅ‰็ซฏ้กต้ข

  • admin.html
  • edit.html
  • login.html
  • detail.html
  • index.html
  • new.html
ๅˆ›ๅปบ้™ๆ€้กต้ขๆœๅŠก-- http-server

npm install http-server -g http-server -p 8001 # ๅˆ›ๅปบๅ‰็ซฏ้™ๆ€่ต„ๆบๆœๅŠก็ซฏๅฃๅทไธบ8001,ๅฏๆŸฅ็œ‹ๅ‰็ซฏhtmlๆ–‡ไปถ

ๅ‰ๅŽ็ซฏ็ซฏๅฃไธไธ€่‡ด--ไฝฟ็”จnginx

  • ๅ‰็ซฏ็ซฏๅฃ๏ผš8001
  • ๅŽ็ซฏ็ซฏๅฃ๏ผš8000

nginxไป‹็ป

  • ้ซ˜ๆ€ง่ƒฝ็š„webๆœๅŠกๅ™จ๏ผŒๅผ€ๆบๅ…่ดน
  • ไธ€่ˆฌ็”จไบŽๅš้™ๆ€ๆœๅŠก๏ผŒ่ดŸ่ฝฝๅ‡่กก
  • ๅๅ‘ไปฃ็†
    • ๆญฃๅ‘ไปฃ็†:ๅฎขๆˆท็ซฏๆŽงๅˆถ็š„ไปฃ็†
    • ๅๅ‘ไปฃ็†๏ผšๅฏนไบŽๅฎขๆˆท็ซฏๆ˜ฏไธ€ไธช้ป‘็›’็š„server็ซฏไปฃ็†

nginxๅๅ‘ไปฃ็†

  • ๆต่งˆๅ™จ---> localhost/index.html ---> nginx ---> / ---> html
  • ๆต่งˆๅ™จ---> localhost/index.html ---> nginx ---> /api/... ---> nodejs

nginxไธ‹่ฝฝ Windows
Mac brew install nginx

nginx้…็ฝฎ Windows:C:\nginx\conf\nginx.conf Mac:/usr/local/etc/nginx/nginx.conf

nginxๅ‘ฝไปค

nginx -t        # ๆต‹่ฏ•้…็ฝฎๆ–‡ไปถๆ ผๅผๆ˜ฏๅฆๆญฃ็กฎ 
nginx -s reload # ๅฏๅŠจnginx ้‡ๅฏ
nginx -s stop   # ๅœๆญข
# vim /usr/local/etc/nginx/nginx.conf

worker_processes 2; # ๅฏๅŠจๅ‡ ไธชๅ†…ๆ ธ

location / {
  proxy_pass http://localhost:8001; 
}
location /api/ {
  proxy_pass http://localhost:8000;
  proxy_set_header Host $host;
}

# nginx -t ๆต‹่ฏ•ๆ˜ฏๅฆ้…็ฝฎไปฃ็†ๆˆๅŠŸ

nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful

็™ปๅฝ•ๅŠŸ่ƒฝ-ๆ€ป็ป“

  • cookieๆ˜ฏไป€ไนˆ๏ผŸ sessionๆ˜ฏไป€ไนˆ๏ผŸๅฆ‚ไฝ•ๅฎž็Žฐ็™ปๅฝ•๏ผŸ
  • redisๆ‰ฎๆผ”ไป€ไนˆ่ง’่‰ฒ๏ผŸๆœ‰ไป€ไนˆๆ ธๅฟƒไปทๅ€ผ๏ผŸ
  • nginx็š„ๅๅ‘ไปฃ็†้…็ฝฎ๏ผŒ่”่ฐƒ่ฟ‡็จ‹ไธญ็š„ไฝœ็”จ๏ผŸ

ๆ—ฅๅฟ—

  • ็ณป็ปŸๆฒกๆœ‰ๆ—ฅๅฟ—๏ผŒๅฐฑ็ญ‰ไบŽไบบๆฒกๆœ‰็œผ็›
    • ๆฏๆ—ฅๆต้‡๏ผŸ QPSๅคšๅฐ‘(QPS:ๆฏ็ง’่ฎฟ้—ฎ้‡)๏ผŸ
  • ็ฌฌไธ€๏ผŒ่ฎฟ้—ฎๆ—ฅๅฟ— access log (server็ซฏๆœ€้‡่ฆ็š„ๆ—ฅๅฟ—)
    • ๅฎขๆˆท็ซฏไฟกๆฏ,้กต้ขไฟกๆฏ
    • GET/POST ่ฏทๆฑ‚
    • ๆต่งˆๅ™จไฟกๆฏ,ๅ ๆฏ”
  • ็ฌฌไบŒ๏ผŒ่‡ชๅฎšไน‰ๆ—ฅๅฟ—(ๅŒ…ๆ‹ฌ่‡ชๅฎšไน‰ไบ‹ไปถใ€้”™่ฏฏ่ฎฐๅฝ•็ญ‰);
  • ๆ€Žไนˆ่ฎฐๅฝ•ๆ—ฅๅฟ—๏ผŸ
  • ๆ€Žไนˆๆ‹†ๅˆ†ๆ—ฅๅฟ—๏ผŸๅˆ†ๆžๆ—ฅๅฟ—๏ผŸ

1.็›ฎๅฝ•

  • Nodejs ๆ–‡ไปถๆ“ไฝœ --- Stream ๆต(ไธบไบ†่Š‚็œCPUๅ†…ๅญ˜)
    • ๆ—ฅๅฟ—่ฆๅญ˜ๅ‚จๅˆฐๆ–‡ไปถไธญ -- ้œ€่ฆๆ‹ท่ดๅˆฐๅ…ถไป–ๆ–‡ไปถ๏ผŒๅ‡ๅฐ‘ๆ“ไฝœๆˆๆœฌ
    • ไธบไฝ•ไธๅญ˜ๅ‚จๅˆฐmysqlไธญ๏ผŸ -- ็กฌ็›˜ๆ•ฐๆฎๅบ“๏ผŒ้€‚ๅˆๅคš่กจ่”ๅŠจ็š„ๆŸฅ่กจๆ“ไฝœๅœบๆ™ฏ
    • ไธบไฝ•ไธๅญ˜ๅ‚จๅˆฐredisไธญ๏ผŸ -- ๅ†…ๅญ˜ๆ•ฐๆฎๅบ“๏ผŒๆˆๆœฌๅคช้ซ˜๏ผŒๆ—ฅๅฟ—ๆ“ไฝœไธ้ข‘็น
  • ๆ—ฅๅฟ—ๅŠŸ่ƒฝๅผ€ๅ‘ๅ’Œไฝฟ็”จ
  • ๆ—ฅๅฟ—ๆ–‡ไปถๆ‹†ๅˆ†๏ผŒๆ—ฅๅฟ—ๅ†…ๅฎนๅˆ†ๆž

2.ๆ–‡ไปถ่ฏปๅ†™๏ผŒๆ˜ฏๅฆๅญ˜ๅœจ

  • fs.readFile
  • fs.writeFile
  • fs.exist

3.IOๆ“ไฝœ็š„ๆ€ง่ƒฝ็“ถ้ขˆ

  • IO ๅŒ…ๆ‹ฌ"็ฝ‘็ปœIO" ๅ’Œ "ๆ–‡ไปถIO"
  • ็›ธๅฏนไบŽCPU่ฎก็ฎ—ๅ’Œๅ†…ๅญ˜่ฏปๅ†™๏ผŒIO็š„็ชๅ‡บ็‰น็‚นๅฐฑๆ˜ฏ๏ผšๆ…ข๏ผ
  • ๅฆ‚ไฝ•ๅœจๆœ‰้™็š„็กฌไปถ่ต„ๆบไธ‹ๆ้ซ˜IO็š„ๆ“ไฝœๆ•ˆ็އ๏ผŸ

4.stream--่งฃๆ”พCPUๅ†…ๅญ˜

  • ๆ ‡ๅ‡†่พ“ๅ…ฅ่พ“ๅ‡บ๏ผŒpipeๅฐฑๆ˜ฏ็ฎก้“๏ผˆ็ฌฆๅˆๆฐดๆต็ฎก้“็š„ๆจกๅž‹ๅ›พ๏ผ‰
  • process.stdin่Žทๅ–ๆ•ฐๆฎ๏ผŒ็›ดๆŽฅ้€š่ฟ‡็ฎก้“ไผ ้€’็ป™ process.stdout
process.stdin.pipe(process.stdout)

node index.js

### ็ป“ๆžœ ่พ“ๅ…ฅ123 ๅ›ž่ฝฆๅฐฑๆ˜ฏๅฏนๅบ”็š„ๅ†…ๅฎน
123
123
231231231
231231231
  • ๆ–‡ไปถIOๆ“ไฝœ
# ๅฐ† 1.txtๆ–‡ไปถๅ†…ๅฎน ๅคๅˆถๅˆฐ 2.txt
const fs = require('fs');
const path = require('path');

const filename1 = path.resolve(__dirname,'./1.txt');
const filename2 = path.resolve(__dirname,'./2.txt');

const readStream = fs.createReadStream(filename1);
const writeStream = fs.createWriteStream(filename2);

//ๅฐ†ๆ–‡ไปถ1.txt็š„ๅ†…ๅฎน้€š่ฟ‡ๆต็š„ๆ–นๅผ ๅคๅˆถๅˆฐ 2.txt
readStream.pipe(writeStream);

//็›‘ๅฌๅ˜ๅŒ–
readStream.on('data',chunk => {
    console.log(chunk.toString());
});
readStream.on('end',() => {
  console.log('copy done');
});
  • ็ฝ‘็ปœIOๆ“ไฝœ
# ็ฝ‘็ปœIOๆ“ไฝœ,ๅฐ†1.txtๆ–‡ๆœฌๅ†…ๅฎน้€š่ฟ‡ๆต่ฟ”ๅ›ž่‡ณๅฎขๆˆท็ซฏ
const http = require('http');
const fs = require('fs');
const path = require('path');

//ๅฐ†ๆ–‡ไปถ1็š„ๅ†…ๅฎน้€š่ฟ‡stream่พ“ๅ‡บ่ฟ”ๅ›ž่‡ณๅฎขๆˆท็ซฏ -- 1
const filename1 = path.resolve(__dirname,'./1.txt');

const server = http.createServer((req,res)=>{
  if(req.method === "GET"){
     const readStream = fs.createReadStream(filename1); //2
     readStream.pipe(res); //3
  } 
})
server.listen(8005);

ไปฃ็ ไธญ่ฎฐๅฝ•่ฎฟ้—ฎๆ—ฅๅฟ—

# utils/log.js
const fs =require('fs');
const path = require('path');

//็”Ÿๆˆwrite stream
function createWriteStream(fileName){
     const fullFileName = path.resolve(__dirname,'./','../','logs',fileName);
     const writeStream = fs.createWriteStream(fullFileName,{
        flags:'a' //append ่ฟฝๅŠ ๅ†™ๆ—ฅๅฟ—
     });
     return writeStream;
}

const accessWriteStream = createWriteStream('access.log');

function writeLog(writeStream,log){
  writeStream.write(log + '\n'); //ๅ…ณ้”ฎ
}
function access(log){
  writeLog(accessWriteStream,log);
}

module.exports = {
  access
}

# ไฝฟ็”จ
const { access }  = require('./utils/log');
//่ฎฐๅฝ• access log
access(`${req.method} -- ${req.url} -- ${req.headers['user-agent']} -- ${Date.now()}`);

ๆ—ฅๅฟ—ๆ‹†ๅˆ†

  • ๆ—ฅๅฟ—ๅ†…ๅฎนไผšๆ…ขๆ…ข็งฏ็ดฏ๏ผŒๆ”พๅœจไธ€ไธชๆ–‡ไปถไธญไธๅฅฝๅค„็†
  • ๆŒ‰ๆ—ถ้—ดๅˆ’ๅˆ†ๆ—ฅๅฟ—ๆ–‡ไปถ๏ผŒๅฆ‚ 2019-08-13.access.logs
  • ๅฎž็Žฐๆ–นๅผ: linux็š„crontabๅ‘ฝไปค,ๅณๅฎšๆ—ถไปปๅŠก
crontab
  • ่ฎพ็ฝฎๅฎšๆ—ถไปปๅŠก ๆ ผๅผ *****command ==> minute/hour/day/month/week command ้กบๅบ๏ผšๅˆ† ๆ—ถ ๆ—ฅ ๆœˆ ๅ‘จ shell่„šๆœฌ ไพ‹ๅฆ‚
5****command ่กจ็คบ ๆฏ5ๅˆ†้’Ÿๆ‰ง่กŒ่ฏฅๅ‘ฝไปค
*1***command ่กจ็คบ ๆฏๅคฉ็š„็ฌฌ1ไธชๅฐๆ—ถๆ‰ง่กŒ่ฏฅๅ‘ฝไปค
**5**command ่กจ็คบ ๆฏไธชๆœˆ5ๅทๆ‰ง่กŒ่ฏฅๅ‘ฝไปค
***5*command ่กจ็คบ 5ๆœˆ1ๅทๆ‰ง่กŒ่ฏฅๅ‘ฝไปค
****5command ่กจ็คบ ๆฏๅ‘จ5ๆ‰ง่กŒ่ฏฅๅ‘ฝไปค

ๅ†ๆฏ”ๅฆ‚

## ๅˆ†้’Ÿ ##
* * * * * command        ๆฏ1ๅˆ†้’Ÿๆ‰ง่กŒไธ€ๆฌกcommand
3,15 * * * * command     ๆฏๅฐๆ—ถ็š„็ฌฌ3ๅ’Œ็ฌฌ15ๅˆ†้’Ÿๆ‰ง่กŒ

## ๅฐๆ—ถ ##
* */1 * * * /etc/init.d/smb restart ๆฏไธ€ๅฐๆ—ถ้‡ๅฏsmb
* 23-7/1 * * * /etc/init.d/smb restart ๆ™šไธŠ11็‚นๅˆฐๆ—ฉไธŠ7็‚นไน‹้—ด๏ผŒๆฏ้š”ไธ€ๅฐๆ—ถ้‡ๅฏsmb
30 21 * * * /etc/init.d/smb restart ๆฏๆ™š็š„21:30้‡ๅฏsmb
0,30 18-23 * * * /etc/init.d/smb restart ๆฏๅคฉ18 : 00่‡ณ23 : 00ไน‹้—ดๆฏ้š”30ๅˆ†้’Ÿ้‡ๅฏsmb
3,15 8-11 * * * command  ๅœจไธŠๅˆ8็‚นๅˆฐ11็‚น็š„็ฌฌ3ๅ’Œ็ฌฌ15ๅˆ†้’Ÿๆ‰ง่กŒ

## ๆ—ฅๆœŸ ## 
3,15 8-11 */2 * * command ๆฏ้š”ไธคๅคฉ็š„ไธŠๅˆ8็‚นๅˆฐ11็‚น็š„็ฌฌ3ๅ’Œ็ฌฌ15ๅˆ†้’Ÿๆ‰ง่กŒ
45 4 1,10,22 * * /etc/init.d/smb restart ๆฏๆœˆ1ใ€10ใ€22ๆ—ฅ็š„4 : 45้‡ๅฏsmb

## ๆœˆไปฝ ##
0 4 1 jan * /etc/init.d/smb restart ไธ€ๆœˆไธ€ๅท็š„4็‚น้‡ๅฏsmb

## ๅ‘จ ##
3,15 8-11 * * 1 command  ๆฏไธชๆ˜ŸๆœŸไธ€็š„ไธŠๅˆ8็‚นๅˆฐ11็‚น็š„็ฌฌ3ๅ’Œ็ฌฌ15ๅˆ†้’Ÿๆ‰ง่กŒ
10 1 * * 6,0 /etc/init.d/smb restart ๆฏๅ‘จๅ…ญใ€ๅ‘จๆ—ฅ็š„1:10้‡ๅฏsmb 
0 11 4 * mon-wed /etc/init.d/smb restart ๆฏๆœˆ็š„4ๅทไธŽๆฏๅ‘จไธ€ๅˆฐๅ‘จไธ‰็š„11็‚น้‡ๅฏsmb
crontabๅ‘ฝไปคๅ’Œๆ—ฅๅฟ—็š„่ฟ็”จๅœบๆ™ฏ
  • ๅฐ†access.logๆ‹ท่ดๅนถ้‡ๅ‘ฝๅไธบ2019-11-2.access.log
  • ๆธ…็ฉบaccess.logๆ–‡ไปถ๏ผŒ็ปง็ปญ็งฏ็ดฏๆ—ฅๅฟ—
#### ็ผ–ๅ†™shell่„šๆœฌ ####
#!/bin/sh
cd /Users/yuxiaoyang03/Desktop/learning/Node-Blog/blog-1/logs // ๅˆฐlog็š„็›ฎๅฝ•ไธ‹
cp access.log $(date +%Y-%m-%d).access.log  // ๅฐ†access.logๆ นๆฎๆ—ถ้—ดๆ—ฅๆœŸ้‡ๅ‘ฝๅ
echo "" > access.log // ๆธ…็ฉบaccess.log
#### ่ฎพ็ฝฎๅฎšๆ—ถไปปๅŠก ####
crontab -e 

#### ็ผ–ๅ†™ๅฎšๆ—ถไปปๅŠก ๆฏๅคฉๅ‡Œๆ™จ0็‚น0ๅˆ†ๆ‰ง่กŒshell่„šๆœฌ ####
* 0 * * * sh /Users/yuxiaoyang03/Desktop/learning/Node-Blog/blog-1/utils/copyLog.sh 

#### ๆŸฅ็œ‹ๅทฒ็ป่ฎพ็ฝฎ็š„ๅฎšๆ—ถไปปๅŠก ####
crontab -l 

ๆ—ฅๅฟ—ๅˆ†ๆž -- readline

  • ๅฆ‚้’ˆๅฏนaccess.logๆ—ฅๅฟ—๏ผŒๅˆ†ๆžChrome็š„ๅ ๆฏ”
  • ๆ—ฅๅฟ—ๆ˜ฏๆŒ‰่กŒๅญ˜ๅ‚จ็š„๏ผŒไธ€่กŒๅฐฑๆ˜ฏไธ€ๆกๆ—ฅๅฟ—
  • ไฝฟ็”จNode็š„readline(ๅŸบไบŽstream๏ผŒๆ•ˆ็އ้ซ˜)
// readlineไฝฟ็”จๆญฅ้ชค
const readline = require('readline');
const fileName = path.join(__dirname, '../logs/access.log'); //ๆ‰พ่ฆๅˆ†ๆž็š„ๆ—ฅๅฟ—
const readStream = fs.createReadStream(fileName); // ๅˆ›ๅปบreadstream
const rl = readline.createInterface({
  input: readStream
});// ๅˆ›ๅปบreadlineๅฏน่ฑก
rl.on('line',()=>{});
rl.on('close',()=>{});
ไปฃ็ 
  • ๅฐ† http://localhost:8000/api/blog/list ๅœจChrome/Safari/Firefox้‡Œ้ขๆ‰ง่กŒๅ‡ ้ๅœจaccess.log้‡Œไบง็”Ÿๆ—ฅๅฟ—ๅ†…ๅฎน
  • ๅˆ›ๅปบ utils/readline.js
const fs = require('fs');
const path = require('path');
const readline = require('readline');

// ๅฏปๆ‰พ็›ฎๆ ‡ๆ—ฅๅฟ—ๆ–‡ไปถ
const fileName = path.join(__dirname, '../logs/access.log');

// ๅˆ›ๅปบ่ฏปๅ–ๆต 
const readStream = fs.createReadStream(fileName);

// ๅˆ›ๅปบreadlineๅฏน่ฑก
const rl = readline.createInterface({
  input: readStream
});

// ่ฎกๆ•ฐๅ™จ
let chromeNum = 0;
let sum = 0;

// ้€่กŒ่ฏปๅ–
rl.on('line', (lineData) => {
  if (!lineData) {
    return;
  };
  sum++;

  // ่Žทๅ–Chromeๆต่งˆๅ™จ็š„ๆ—ฅๅฟ—ไฟกๆฏ
  // GET -- /api/blog/list -- Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36 -- 1572693248592
  let logArr = lineData.split(' -- '); // ๆ นๆฎ--ๆ—ฅๅฟ—ๆ ผๅผๆ‹†ๅˆ†
  if (logArr[2] && logArr[2].indexOf('Chrome') > 0) {
    chromeNum++;
  }
});

rl.on('close', () => {
  let res = parseFloat(chromeNum / sum).toFixed(2) * 100 + "%";
  console.log('chromeๆต่งˆๅ™จๅ ๆฏ”:' + res);
});
  • ๆ‰ง่กŒ node ./utils/readline.js

ๆ€ป็ป“

  • ๆ—ฅๅฟ—ๅฏนไบŽserver็ซฏๅพˆ้‡่ฆ๏ผŒๅฐฑๅƒ็œผ็›
  • IOๆ€ง่ƒฝ็“ถ้ขˆ๏ผŒไฝฟ็”จstreamๆ้ซ˜ๆ€ง่ƒฝ
  • ไฝฟ็”จcrontabๆ‹†ๅˆ†ๆ—ฅๅฟ—ๆ–‡ไปถ
  • ไฝฟ็”จreadlineๅˆ†ๆžๆ—ฅๅฟ—ๅ†…ๅฎน

ๅฎ‰ๅ…จ

  • SQLๆณจๅ…ฅ:็ชƒๅ–ๆ•ฐๆฎๅบ“ๅ†…ๅฎน
  • XSSๆ”ปๅ‡ป:็ชƒๅ–ๅ‰็ซฏ็š„cookie็š„ๅ†…ๅฎน
  • ๅฏ†็ ๅŠ ๅฏ†:ไฟๆŠค็”จๆˆทไฟกๆฏๅฎ‰ๅ…จ(้‡่ฆ๏ผ๏ผ)

SQLๆณจๅ…ฅ

  • ๆœ€ๅŽŸๅง‹ใ€ๆœ€็ฎ€ๅ•็š„ๆ”ปๅ‡ป๏ผŒไปŽweb2.0ๅฐฑๆœ‰ไบ†
  • ๆ”ปๅ‡ปๆ–นๅผ:่พ“ๅ…ฅไธ€ไธชsql็‰‡ๆฎต๏ผŒๆœ€็ปˆๆ‹ผๆŽฅๆˆไธ€ๆฎตๆ”ปๅ‡ปไปฃ็ 
  • ้ข„้˜ฒๆŽชๆ–ฝ:ไฝฟ็”จmysql็š„escapeๅ‡ฝๆ•ฐๅค„็†่พ“ๅ…ฅๅ†…ๅฎนๅณๅฏ
# ๆญฃๅธธ็š„sql
select username,realname from users where username='zhangsan'and password='123';

# ๅฆ‚ๆžœๅœจ็”จๆˆทๅๅค„่พ“ๅ…ฅ โ€œzhangsan' --โ€ ๅฐฑไผšๅฏผ่‡ดsqlๆณจๅ…ฅ
select username,realname from users where username='zhangsan' -- 'and password='123';

# ่ฟ™ๆ ทๅŠ ไธŠโ€œ'zhangsan;delete from users -- โ€ๅฐฑๅฎŒ่›‹ไบ† users่กจๅฐฑๆฒกไบ†
select username,realname from users where username='zhangsan';delete from users -- 'and password='123';

# ้˜ฒ่Œƒ -- ๅˆฉ็”จmysql.escape()
username = mysql.escape(username)
password = mysql.escape(password)

## escape่ฝฌไน‰ไบ†็ฌฆๅท ๆ‰€ไปฅ่พพๅˆฐไบ†้˜ฒๆญขsqlๆณจๅ…ฅ็š„ๅŠŸ่ƒฝ
select username,realname from users where username='zhangsan\' -- 'and password='123';

XSSๆ”ปๅ‡ป

  • ๅ‰็ซฏๅŒๅญฆๆœ€็†Ÿๆ‚‰็š„ๆ”ปๅ‡ปๆ–นๅผ๏ผŒไฝ†server็ซฏๆ›ดๅบ”่ฏฅๆŽŒๆก
  • ๆ”ปๅ‡ปๆ–นๅผ:ๅœจ้กต้ขๅฑ•็คบๅ†…ๅฎนไธญๆŽบๆ‚jsไปฃ็ ๏ผŒไปฅ่Žทๅ–็ฝ‘้กตไฟกๆฏ
  • ้ข„้˜ฒๆŽชๆ–ฝ:่ฝฌๆข็”Ÿๆˆjs็š„็‰นๆฎŠๅญ—็ฌฆ
// xssๆ”ปๅ‡ป ๅพ€ๆ–‡ๆœฌๆก†้‡Œ่พ“ๅ…ฅjsไปฃ็ 
<script>alert(document.cookie)</script>

// ่ฝฌๆข็‰นๆฎŠๅญ—็ฌฆ
& --> &amp;
< --> &it;
> --> &gt;
" --> &quot;
' --> &#x27;
/ --> &#x2F;

// ๅฏไปฅๅฎ‰่ฃ…xssๅทฅๅ…ทๅŒ…
npm i xss --save
title = xss(title);
content = xss(content);

ๅฏ†็ ๅŠ ๅฏ† -- cryptoๅŠ ๅฏ†ๅบ“

  • ๆ•ฐๆฎๅบ“่ขซ็”จๆˆทๆ”ป็ ด๏ผŒๆœ€ไธๅบ”่ฏฅๆณ„ๆผ็š„ๅฐฑๆ˜ฏ็”จๆˆทไฟกๆฏ
  • ๆ”ปๅ‡ปๆ–นๅผ:่Žทๅ–็”จๆˆทๅๅ’Œๅฏ†็ ,ๅ†ๅŽปๅฐ่ฏ•็™ปๅฝ•ๅ…ถไป–็ณป็ปŸ
  • ้ข„้˜ฒๆŽชๆ–ฝ:ๅฐ†ๅฏ†็ ๅŠ ๅฏ†๏ผŒๅณไพฟๆ‹ฟๅˆฐๅฏ†็ ไนŸไธๆ˜พ็คบๆ˜Žๆ–‡
// ๅŽŸ็†: ่‡ชๅฎšไน‰็š„key + ๅฏ†็  --> ๅŠ ๅฏ†็š„ๆˆณ
let SELECT_KEY = 'AbcD_123123##';
let content = `password=${password}&key=${SELECT_KEY}`;
let md5Pass = crypto.createHash('md5').update(content).digest('hex'); //ๆœ€็ปˆๅŠ ๅฏ†็š„ๅฏ†็ 

// ๅฐ†zhangsan็š„ๅฏ†็ ๆ›ดๆ–ฐไธบๅŠ ๅฏ†ไน‹ๅŽ็š„'eb0c2f011e4adb48ad2802321a8c132f'
// ๆ›ดๆขๅฏ†็ ้•ฟๅบฆ ๅณๅ‡ปusers่กจ --> Alter Table --> VARCHAR(20) ๆ”นไธบ VARCHAR(32)

ๆ€ป็ป“-- ไธไฝฟ็”จๆก†ๆžถๅผ€ๅ‘server็š„ๆ€ป็ป“

  • ๅผ€ๅ‘ไบ†ๅ“ชไบ›ๅŠŸ่ƒฝๆจกๅ—๏ผŒๅฎŒๆ•ด็š„ๆต็จ‹

    • ๅŠŸ่ƒฝๆจกๅ—
      • ๅค„็†httpๆŽฅๅฃ
      • ่ฟžๆŽฅๆ•ฐๆฎๅบ“
      • ๅฎž็Žฐ็™ปๅฝ•
      • ๅฎ‰ๅ…จ
      • ๆ—ฅๅฟ—
      • ไธŠ็บฟ
    • ๆต็จ‹ ๆต่งˆๅ™จ ---> nginx ---> /.. ---> ้™ๆ€ๆ–‡ไปถhtml/css/js/img ---> /api/.. ---> ๆ—ฅๅฟ—่ฎฐๅฝ•(ๆ—ฅๅฟ—ๆ–‡ไปถ)/่ทฏ็”ฑๅค„็†/็™ป้™†ๆ ก้ชŒ(redis)/็”จๆˆทไฟกๆฏ(redis)/ๆ•ฐๆฎๅค„็†(mysql)
  • ็”จๅˆฐไบ†ๅ“ชไบ›ๆ ธๅฟƒ็Ÿฅ่ฏ†็‚น

    • http,nodejsๅค„็†httpใ€ๅค„็†่ทฏ็”ฑใ€mysql
    • cookieใ€sessionใ€redisใ€nginxๅๅ‘ไปฃ็†
    • ๅฎ‰ๅ…จ็Ÿฅ่ฏ†:sqlๆณจๅ…ฅใ€xssๆ”ปๅ‡ปใ€ๅฏ†็ ๅŠ ๅฏ†
    • ๆ—ฅๅฟ—ใ€streamใ€contrabใ€readline
  • ๅ›ž้กพ serverๅ’Œๅ‰็ซฏ็š„ๅŒบๅˆซ

    • ๆœๅŠก็จณๅฎšๆ€ง
    • ๅ†…ๅญ˜CPUไผ˜ๅŒ–ๆ‰ฉๅฑ•
    • ๆ—ฅๅฟ—่ฎฐๅฝ•
    • ๅฎ‰ๅ…จ(ๅŒ…ๆ‹ฌ็™ปๅฝ•้ชŒ่ฏ)
    • ้›†็พคๅ’ŒๆœๅŠกๆ‹†ๅˆ†

express

  • Nodejsๆœ€ๅธธ็”จ็š„web server
  • ไธ‹่ฝฝใ€ๅฎ‰่ฃ…ใ€ไฝฟ็”จใ€expressไธญ้—ดไปถๆœบๅˆถ
  • ๅผ€ๅ‘ๆŽฅๅฃใ€่ฟžๆŽฅๆ•ฐๆฎๅบ“ใ€ๅฎž็Žฐ็™ปๅฝ•ใ€ๆ—ฅๅฟ—่ฎฐๅฝ•
  • ๅˆ†ๆžexpressไธญ้—ดไปถๅŽŸ็†

ไป‹็ปexpress

  • ๅฎ‰่ฃ…--express-generator่„šๆ‰‹ๆžถ
    • sudo npm i express-generator -g
    • express blog-express
    • npm i & npm start
    • npm i cross-env nodemon -D
  • ๅˆๅง‹ๅŒ–ไปฃ็ ไป‹็ปใ€ๅค„็†่ทฏ็”ฑ
  • ไฝฟ็”จไธญ้—ดไปถ

app.js

  • ๅ„ไธชๆ’ไปถ็š„ไฝœ็”จ
  • ๆ€่€ƒๆ›ดๆ’ไปถ็š„ๅฎž็ŽฐๅŽŸ็†
  • ๅค„็†get/post่ฏทๆฑ‚

ไธญ้—ดไปถๆœบๅˆถ

  • app.use(ไธญ้—ดไปถๅ‡ฝๆ•ฐ)
  • app.get(ไธญ้—ดไปถๅ‡ฝๆ•ฐ)
  • app.post(ไธญ้—ดไปถๅ‡ฝๆ•ฐ)

ๅ…ทไฝ“ๅผ€ๅ‘็ป†่Š‚

1.ๆ‰“้€šๆ•ฐๆฎๅบ“ๅ’ŒๆŽฅๅฃ--ๅคง้ƒจๅˆ†ๅค็”จblog-1้‡Œ็š„ไปฃ็ 

2.ไฝฟ็”จexpress-sessionๅ’Œconnect-redisๅฎž็Žฐ็™ปๅฝ•้ชŒ่ฏ

req.sessionไฟๅญ˜็™ปๅฝ•ไฟกๆฏ -- express-session

  • npm i express-session
// app.js
const session = require('express-session');
app.use(session({
  secret: 'AAAbbb_123##',
  cookie: {
    path: '/', //้ป˜่ฎค
    httpOnly: true,//้ป˜่ฎค
    maxAge: 24 * 60 * 60 * 100
  }
}));
// user.js
/** ๆต‹่ฏ•sessionๆ˜ฏๅฆๆˆๅŠŸ
 * http://localhost:3000/api/user/session-test 
 * ้€š่ฟ‡ๅœจไธๅŒๆต่งˆๅ™จ็š„่ฟ”ๅ›žๅฏไปฅ็œ‹ๅˆฐไธๅŒ็š„ๆ•ฐๅญ—๏ผŒ่ฏดๆ˜Žsession้…็ฝฎๆˆๅŠŸ
 */
router.get('/session-test',(req,res,next)=>{
    const session = req.session;
    if(!session.vieNum){
      session.vieNum = 0
    }
    session.vieNum ++;
    res.json({
      vieNum:session.vieNum
    })
})

็ผ–ๅ†™ /api/user/loginๆŽฅๅฃ

ๅŽŸ็†:็™ป้™†ๅฎŒๅœจๆœๅŠก็ซฏ่ฎฐๅฝ•session็”จๆˆทไฟกๆฏ,ๅœจ้€š่ฟ‡login-test้ชŒ่ฏๆ˜ฏๅฆๅทฒ็™ปๅฝ•

router.get('/login-get', function(req, res, next) {
  const { username,password } = req.query;
  return loginCheck(username,password).then(loginRes => {
   if(loginRes.username){
     req.session.username = loginRes.username;
     req.session.realname = loginRes.realname;
   
     res.json(new SuccessModel('็™ป้™†ๆˆๅŠŸ!'));
     return;
    }
    res.json(new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!'));
  });
});
/** ๆต‹่ฏ•/loginๆ˜ฏๅฆๆˆๅŠŸ
 * http://localhost:3000/api/user/login-get?username=zhangsan&password=123 ่ฟ™้‡Œ็”จgetๆจกๆ‹Ÿpost็™ปๅฝ•
 * http://localhost:3000/api/user/login-test ๆต‹่ฏ•ๆ˜ฏๅฆๅทฒ็™ปๅฝ•
 */
router.get('/login-test',(req,res,next)=>{
  const session = req.session;
  if(session.username){
    res.json({
      res:'ๅทฒ็™ปๅฝ•'
    })
    return
  }
  res.json({
    res:'็™ปๅฝ•ๅคฑ่ดฅ'
  })
});
// ๅฎž้™…็™ปๅฝ•ไฝฟ็”จ็š„ๆ˜ฏpost
router.post('/login', function(req, res, next) {
  const { username,password } = req.body;
  return loginCheck(username,password).then(loginRes => {
   if(loginRes.username){
     req.session.username = loginRes.username;
     req.session.realname = loginRes.realname;
   
     res.json(new SuccessModel('็™ป้™†ๆˆๅŠŸ!'));
     return;
    }
    res.json(new ErrorModel('็™ปๅฝ•ๅคฑ่ดฅ!'));
  });
});

ไฝฟ็”จconnect-redisๅญ˜ๅ‚จ็”จๆˆทsessionไฟกๆฏ

  • npm i redis connect-redis
// 1 ่Žทๅ–redisๅฎขๆˆท็ซฏ db/redis.js
const redis = require('redis');
const { REDIS_CONF } = require('./conf');
const { port , host } = REDIS_CONF;

//ๅˆ›ๅปบๅฎขๆˆท็ซฏ
const redisClient = redis.createClient(port,host);

redisClient.on('error',err => {
    console.error(err);
});

module.exports = redisClient;
// app.js ่ฟžๆŽฅ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({
  store:sessionStore
}))
  • ๆต‹่ฏ•redisไธญๆ˜ฏๅฆๅทฒ็ปๅญ˜ๅ‚จไบ†็”จๆˆท็š„key
redis-cli
่ฎฟ้—ฎ http://localhost:3000/api/user/login-get?username=zhangsan&password=123
keys *
127.0.0.1:6379> keys *
1) "sess:VKNIoVD6i8u6pTgksuzfCBOQEU67YDJt" # ่กจ็คบๅญ˜่ฟ›ๅŽปไบ†

# ่Žทๅ–็”จๆˆทไฟกๆฏ
get sess:VKNIoVD6i8u6pTgksuzfCBOQEU67YDJt
"{\"cookie\":{\"originalMaxAge\":8640000,\"expires\":\"2019-11-03T11:49:33.851Z\",\"httpOnly\":true,\"path\":\"/\"},\"username\":\"zhangsan\",\"realname\":\"\xe5\xbc\xa0\xe4\xb8\x89\"}" ---> ็”จๆˆทไฟกๆฏ

็™ปๅฝ•ๆ ก้ชŒ--ๅšๆˆexpressไธญ้—ดไปถ

3.ๆ—ฅๅฟ—ๅˆ†ๆž--morgan

const ENV = process.env.NODE_ENV
if(ENV !== 'production'){
  // ่งฃๆžๅผ€ๅ‘็Žฏๅขƒ ๆ—ฅๅฟ—
  app.use(logger('dev')); 
  // GET /api/blog/list 304 10.089 ms - - ๆ—ฅๅฟ—ๆ ผๅผ
}else{
  // ่งฃๆž็บฟไธŠ็Žฏๅขƒ ๆ—ฅๅฟ—
  const logFile = path.join(__dirname,'./logs/access.log');
  const writeStream = fs.createWriteStream(logFile,{
    flags:'a'
  });
  app.use(logger('combined',{
    stream:writeStream
  })); 
  //::1 - - [03/Nov/2019:11:18:04 +0000] "GET /api/blog/list HTTP/1.1" 304 - "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"
}

4.ไบ†่งฃexpress็š„ไธญ้—ดไปถๅŽŸ็† -- app.use/get/postๆ€Žไนˆๆ”ถ้›†ๅ‚ๆ•ฐ๏ผŸnextๆ€Žไนˆ่งฆๅ‘๏ผŸ

Koa2

  • expressไธญ้—ดไปถๆ˜ฏๅผ‚ๆญฅๅ›ž่ฐƒ๏ผŒkoa2ๅŽŸ็”Ÿๆ”ฏๆŒasync/await
  • ๆ–ฐๆก†ๆžถๅผ€ๅ‘ๆก†ๆžถๅ’Œ็ณป็ปŸ๏ผŒ้ƒฝๅŸบไบŽkoa2๏ผŒไพ‹ๅฆ‚egg.js

็›ฎๅฝ•

  • aysnc/await ่ฏญๆณ•ไป‹็ป ๅฎ‰่ฃ…ๅ’Œไป‹็ปkoa2
  • ๅผ€ๅ‘ๆŽฅๅฃ๏ผŒ่ฟžๆŽฅๆ•ฐๆฎๅบ“๏ผŒๅฎž็Žฐ็™ปๅฝ•๏ผŒๆ—ฅๅฟ—่ฎฐๅฝ•
  • ๅˆ†ๆžkoa2ไธญ้—ดไปถๅŽŸ็†

aysnc/await ่ฏญๆณ•ไป‹็ป

  • aysnc ๅ‡ฝๆ•ฐๆ‰ง่กŒ่ฟ”ๅ›žpromiseๅฏน่ฑก
  • await ๅŽ ๅฏๆ‰ง่กŒpromiseๅฏน่ฑก
  • await ๅฟ…้กปๅŒ…่ฃนๅœจ asyncๅ‡ฝๆ•ฐๅ†…
  • try-catchๅฏไปฅๆˆช่Žทpromiseไธญreject็š„ๅ€ผ
async function getRes() {
  try {
    const aData = await getFileContent('1.json');
    console.log(aData);

    const bData = await getFileContent(aData.next);
    console.log(bData);

    const cData = await getFileContent(bData.next);
    console.log(cData);
  } catch (err) {
    console.error(err);
  }
}
getRes()

ๅฎ‰่ฃ…ๅ’Œไป‹็ปkoa2

  • ๅฎ‰่ฃ… ไฝฟ็”จkoa-generator
    • npm i koa-generator
    • Koa2 my-test
    • npm i & npm run dev
    • npm i cross-env ่„šๆ‰‹ๆžถๆฒกๆœ‰้…็ฝฎ็Žฏๅขƒๅ‚ๆ•ฐ๏ผŒ้œ€่ฆๆ‰‹ๅŠจ้…็ฝฎ
    "dev": "cross-env NODE_ENV=dev ./node_modules/.bin/nodemon bin/www",
    "prd": "cross-env NODE_ENV=production pm2 start bin/www",
  • ๅˆๅง‹ๅŒ–ไปฃ็  ๅค„็†่ทฏ็”ฑ

    // routes/user.js
    const router = require('koa-router')()
    
    router.prefix('/api/user')
    router.get('/', async (ctx, next) => {
      ctx.body ={
        title:'123'
      }
    })
    module.exports = router
    
      // app.js
      const user = require('./routes/user'); // ๅผ•ๅ…ฅ่ทฏ็”ฑๆ–‡ไปถ
      app.use(user.routes(), user.allowedMethods()); // ๆณจๅ†Œ่ทฏ็”ฑ
    
  • ไฝฟ็”จไธญ้—ดไปถ

ๅผ€ๅ‘ๆŽฅๅฃ

  • ๅฎž็Žฐ็™ปๅฝ•

    • koa-gengeric-session ๅ’Œ koa-redis
    • npm i koa-generic-session koa-redis redis
      // app.js
      const session = require('koa-generic-session');
      const redisStore = require('koa-redis');
      
      // connect redis to save session info
      app.keys = ['AAAbbb_123##'];
      app.use(session({
        store: redisStore({
          all:'127.0.0.1:6379' //ๆœฌๅœฐๅ†™ๆญป
        }),
        // ้…็ฝฎcookie
        cookie: {
          path: '/',
          httpOnly: true,
          maxAge: 24 * 60 * 60 * 1000
        }
      }))
    
    • redis-server ๅผ€ๅฏredisๆœๅŠก
    • ็ผ–ๅ†™ๆต‹่ฏ•session็š„ไปฃ็ 
      // routes/user.js
      router.get('/session-test', async (ctx, next) => {
      if (ctx.session.vieNum == null) {
        ctx.session.vieNum = 0
      }
      ctx.session.vieNum++;
      ctx.body = {
        vieNum: ctx.session.vieNum
      }
    })
    
  • ๅผ€ๅ‘ๆŽฅๅฃ

  • ่ฎฐๅฝ•ๆ—ฅๅฟ— -- ็ปง็ปญไฝฟ็”จmorgan

    • ไฝฟ็”จkoa-smorgan
    • ่‡ชๅฎšไน‰ๆ—ฅๅฟ—ไฝฟ็”จconsole.logๅ’Œconsole.error
    • ๆ—ฅๅฟ—ๆ–‡ไปถๆ‹†ๅˆ†
    • ๆ—ฅๅฟ—ๅ†…ๅญ˜ๅˆ†ๆž

koa-generator่„šๆ‰‹ๆžถ่‡ชๅธฆ็š„koa-loggerๅชๆ˜ฏไธบไบ†ๆœฌๅœฐๆœๅŠกๆ—ฅๅฟ—ๆ‰“ๅฐๆ›ดๅŠ ๆผ‚ไบฎ๏ผŒๅฝขๅฆ‚:

POST /api/blog/update?id=2 - 34ms --> POST /api/blog/update?id=2 200 39ms 42b <-- GET /api/blog/list GET /api/blog/list - 2ms --> GET /api/blog/list 200 7ms 231b

const logger = require('koa-logger')
// logger
app.use(async (ctx, next) => {
  const start = new Date()
  await next()
  const ms = new Date() - start
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})

ไฝฟ็”จkoa-morgan

  • npm i koa-morgan
// app.js
const fs = require('fs');
const path = require('path');
const morgan = require('koa-morgan');

// use koa-mogran to save logs
const ENV = process.env.NODE_ENV
if (ENV !== 'production') { // ่งฃๆžๅผ€ๅ‘็Žฏๅขƒ ๆ—ฅๅฟ— ๆ ผๅผ:GET /api/blog/list 200 8.058 ms - 343
  app.use(morgan('dev'));
} 
else { // ่งฃๆž็บฟไธŠ็Žฏๅขƒ ๆ—ฅๅฟ—
  const logFile = path.join(__dirname, './logs/access.log');
  const writeStream = fs.createWriteStream(logFile, {
    flags: 'a'
  });
  app.use(morgan('combined', {
    stream: writeStream
  }));
  // ๆœ€็ปˆ็บฟไธŠ็š„ๆ—ฅๅฟ—ๆ ผๅผ ::1 - - [06/Nov/2019:13:29:19 +0000] "GET /api/blog/list HTTP/1.1" 200 343 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
}

koa2ไธญ้—ดไปถๅŽŸ็†ๅˆ†ๆž -- ๆด‹่‘ฑๅœˆๆจกๅž‹

// test09-koa-test
/** koa -- ๆด‹่‘ฑๅทๆจกๅž‹
1.....็ฌฌไธ€ๅฑ‚ๆด‹่‘ฑ--ๅผ€ๅง‹...
3.......็ฌฌไบŒๅฑ‚ๆด‹่‘ฑ--ๅผ€ๅง‹.
5.......็ฌฌไธ‰ๅฑ‚ๆด‹่‘ฑ--ๅผ€ๅง‹
6.......็ฌฌไธ‰ๅฑ‚ๆด‹่‘ฑ--็ป“ๆŸ
4.....็ฌฌไบŒๅฑ‚ๆด‹่‘ฑ--็ป“ๆŸ...
2.....็ฌฌไธ€ๅฑ‚ๆด‹่‘ฑ--็ป“ๆŸ...
 */
  • 1.app.useๆณจๅ†Œไธญ้—ดไปถ ่ฟ›่กŒๆ”ถ้›†
  • 2.ๅฎž็Žฐnextๆœบๅˆถ๏ผŒไธŠไธ€ไธช้€š่ฟ‡next่งฆๅ‘ไธ‹ไธ€ไธช
  • 3.ไธๆถ‰ๅŠmethodๅ’Œpath

็บฟไธŠ็Žฏๅขƒ

  • ๆœๅŠกๅ™จ็จณๅฎšๆ€ง
  • ๅ……ๅˆ†ๅˆฉ็”จๆœๅŠกๅ™จ็กฌไปถ่ต„ๆบ๏ผŒไปฅไพฟๆ้ซ˜ๆ€ง่ƒฝ
  • ็บฟไธŠๆ—ฅๅฟ—่ฎฐๅฝ•

PM2

  • ่ฟ›็จ‹ๅฎˆๆŠค๏ผŒ็ณป็ปŸๅดฉๆบƒ่‡ชๅŠจ้‡ๅฏ
  • ๅฏๅŠจๅคš่ฟ›็จ‹๏ผŒๅ……ๅˆ†ๅˆฉ็”จCPUๅ’Œๅ†…ๅญ˜
  • ่‡ชๅธฆๆ—ฅๅฟ—่ฎฐๅฝ•ๅŠŸ่ƒฝ

ๅธธ็”จๅ‘ฝไปค

    1. pm2 start app.js
    1. pm2 list
    1. pm2 --version
    1. pm2 restart /
    • ๅฆ‚ๆžœไฟฎๆ”นไบ†ๆœๅŠก้‡Œ้ข็š„ๅ†…ๅฎน๏ผŒ้‡ๅฏๆœๅŠกๅฏไปฅ็›ดๆŽฅไฝฟ็”จ pm2 restart 0 / app Use --update-env to update environment variables [PM2] Applying action restartProcessId on app [0](ids: [ '0' ]) [PM2] app โœ“
โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id โ”‚ name                    โ”‚ version โ”‚ mode    โ”‚ pid      โ”‚ uptime โ”‚ โ†บ    โ”‚ status   โ”‚ cpu      โ”‚ mem      โ”‚ user     โ”‚ watching โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0  โ”‚ app                     โ”‚ 1.0.0   โ”‚ fork    โ”‚ 53536    โ”‚ 0s     โ”‚ 1    โ”‚ online   โ”‚ 0%       โ”‚ 13.1mb   โ”‚ yuxโ€ฆ โ”‚ disabled โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    1. pm2 stop / [PM2] Applying action stopProcessId on app [app](ids: [ 0 ]) [PM2] app โœ“
โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id โ”‚ name                    โ”‚ version โ”‚ mode    โ”‚ pid      โ”‚ uptime โ”‚ โ†บ    โ”‚ status   โ”‚ cpu      โ”‚ mem      โ”‚ user     โ”‚ watching โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0  โ”‚ app                     โ”‚ 1.0.0   โ”‚ fork    โ”‚ 0        โ”‚ 0      โ”‚ 5    โ”‚ stopped  โ”‚ 0%       โ”‚ 0b       โ”‚ yuxโ€ฆ โ”‚ disabled โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    1. pm2 delete / [PM2] Applying action deleteProcessId on app [app](ids: [ 0 ]) [PM2] app โœ“
    1. pm2 info / ๆŸฅ็œ‹ๆœๅŠก็š„ไฟกๆฏ
    1. pm2 log / ๆŸฅ็œ‹ๆ—ฅๅฟ—
  - 0|app  | server is listen on port 7000
    0|app  | cur time 1573129491818
    0|app  | error 1573129491818
    0|app  | cur time 1573129491931
    0|app  | error 1573129491931
    0|app  | cur time 1573129493350
    0|app  | error 1573129493350
    0|app  | cur time 1573129493402
    0|app  | error 1573129493402
  • cat /Users/.../.pm2/logs/app-error.log ๆŸฅ็œ‹้”™่ฏฏๆ—ฅๅฟ—
  • cat /Users/.../.pm2/logs/app-out.log ๆŸฅ็œ‹่พ“ๅ‡บๆ—ฅๅฟ—
    1. pm2 monit / ๆŸฅ็œ‹ๅฝ“ๅ‰้€š่ฟ‡pm2่ฟ่กŒ็š„่ฟ›็จ‹็š„็Šถๆ€๏ผŒๆฏ”ๅฆ‚ๅ†…ๅญ˜ไฟกๆฏ,ๆ—ฅๅฟ—็ญ‰
  โ”Œโ”€ Process List โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”Œโ”€โ”€  app Logs  โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚[ 0] app           Mem:  31 MB    CPU:  0 %  online โ”‚โ”‚ app > cur time 1573129746959                                                                                               โ”‚
โ”‚                                                    โ”‚โ”‚ app > error 1573129746960                                                                                                  โ”‚
โ”‚                                                    โ”‚โ”‚ app > cur time 1573129747028                                                                                               โ”‚
โ”‚                                                    โ”‚โ”‚ app > error 1573129747028                                                                                                  โ”‚
โ”‚                                                    โ”‚โ”‚ app > cur time 1573129747806                                                                                               โ”‚
โ”‚                                                    โ”‚โ”‚ app > error 1573129747806                                                                                                  โ”‚
โ”‚                                                    โ”‚โ”‚ app > cur time 1573129747846                                                                                               โ”‚
|                                                   โ”‚โ”‚ app > error 1573129747846       

่ฟ›็จ‹ๅฎˆๆŠค

// ๆจกๆ‹Ÿ้”™่ฏฏ
  if(req.url === '/err'){
    throw new Error('error')
  }

้‡ๅฏpm2 pm2 restart 0 ่ฎฟ้—ฎ http://localhost:7000/err ้กต้ขๆŒ‚ๆމ pm2 list

โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id โ”‚ name                    โ”‚ version โ”‚ mode    โ”‚ pid      โ”‚ uptime โ”‚ โ†บ    โ”‚ status   โ”‚ cpu      โ”‚ mem      โ”‚ user     โ”‚ watching โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0  โ”‚ app                     โ”‚ 1.0.0   โ”‚ fork    โ”‚ 54999    โ”‚ 0s     โ”‚ 3    โ”‚ online   โ”‚ 0%       โ”‚ 10.8mb   โ”‚ yuxโ€ฆ โ”‚ disabled โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id โ”‚ name                    โ”‚ version โ”‚ mode    โ”‚ pid      โ”‚ uptime โ”‚ โ†บ    โ”‚ status   โ”‚ cpu      โ”‚ mem      โ”‚ user     โ”‚ watching โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0  โ”‚ app                     โ”‚ 1.0.0   โ”‚ fork    โ”‚ 55041    โ”‚ 6s     โ”‚ 5    โ”‚ online   โ”‚ 2.3%     โ”‚ 31.2mb   โ”‚ yuxโ€ฆ โ”‚ disabled โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๅ‘็Žฐrestart็”ฑ3 --> 5

้…็ฝฎpm2.conf.json

  • ๆ–ฐๅปบPM2้…็ฝฎๆ–‡ไปถ(ๅŒ…ๆ‹ฌ่ฟ›็จ‹ๆ•ฐ้‡๏ผŒๆ—ฅๅฟ—ๆ–‡ไปถ็›ฎๅฝ•็ญ‰)
  • ไฟฎๆ”นPM2ๅฏๅŠจๅ‘ฝไปค๏ผŒ้‡ๅฏ
  • ่ฎฟ้—ฎserver๏ผŒๆฃ€ๆŸฅๆ—ฅๅฟ—ๆ–‡ไปถ็š„ๅ†…ๅฎน(ๆ—ฅๅฟ—่ฎฐๅฝ•ๆ˜ฏๅฆ็”Ÿๆ•ˆ)
{
  "apps":{
    "name":"pm2-test-server",
    "script":"app.js",
    "watch":true,
    "ignore_watch":[
      "node_modules",
      "logs"
    ],
    "error_file":"logs/err.log", //ไฟฎๆ”นๆ—ฅๅฟ—็›ฎๅฝ•
    "out_file":"logs/out.log",
    "log_date_format":"YYYY-MM-DD HH:mm:ss"
  }
}
// package.json
  "prd:conf":"cross-env NODE_ENV=production pm2 start pm2.conf.json"

ๅคš่ฟ›็จ‹

ไธบไป€ไนˆไฝฟ็”จๅคš่ฟ›็จ‹

  • ๆ“ไฝœ็ณป็ปŸ้™ๅˆถไธ€ไธช่ฟ›็จ‹็š„ๅ†…ๅญ˜
  • ๅ†…ๅญ˜๏ผ›ๆ— ๆณ•ๅ……ๅˆ†ๅˆฉ็”จๆœบๅ™จๅ…จ้ƒจๅ†…ๅญ˜
  • CPU: ๆ— ๆณ•ๅ……ๅˆ†ๅˆฉ็”จๅคšๆ ธCPU็š„ไผ˜ๅŠฟ

ๅคš่ฟ›็จ‹็š„็ผบ็‚น

  • ๅคš่ฟ›็จ‹ไน‹้—ด๏ผŒๆ— ๆณ•ๅฎž็Žฐๅ†…ๅญ˜ๅ…ฑไบซ
  • ่งฃๅ†ณ: ๅคš่ฟ›็จ‹่ฎฟ้—ฎๅŒไธ€ไธชredis,ๅฎž็Žฐๆ•ฐๆฎๅ…ฑไบซ
// ๆทปๅŠ  instancesๅฑžๆ€ง
{
  "apps":{
    "name":"pm2-test-server",
    "script":"app.js",
    "watch":true,
    "ignore_watch":[
      "node_modules",
      "logs"
    ],
    "error_file":"logs/err.log",
    "out_file":"logs/out.log",
    "log_date_format":"YYYY-MM-DD HH:mm:ss",
    "instances":4
  }
}

npm run prd:conf

โ”Œโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ id โ”‚ name                    โ”‚ version โ”‚ mode    โ”‚ pid      โ”‚ uptime โ”‚ โ†บ    โ”‚ status   โ”‚ cpu      โ”‚ mem      โ”‚ user     โ”‚ watching โ”‚
โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ 0  โ”‚ pm2-test-server         โ”‚ 1.0.0   โ”‚ cluster โ”‚ 56926    โ”‚ 27s    โ”‚ 0    โ”‚ online   โ”‚ 0%       โ”‚ 33.3mb   โ”‚ yuxโ€ฆ โ”‚ enabled  โ”‚
โ”‚ 1  โ”‚ pm2-test-server         โ”‚ 1.0.0   โ”‚ cluster โ”‚ 56927    โ”‚ 27s    โ”‚ 0    โ”‚ online   โ”‚ 0%       โ”‚ 33.0mb   โ”‚ yuxโ€ฆ โ”‚ enabled  โ”‚
โ”‚ 2  โ”‚ pm2-test-server         โ”‚ 1.0.0   โ”‚ cluster โ”‚ 56932    โ”‚ 27s    โ”‚ 0    โ”‚ online   โ”‚ 0%       โ”‚ 32.0mb   โ”‚ yuxโ€ฆ โ”‚ enabled  โ”‚
โ”‚ 3  โ”‚ pm2-test-server         โ”‚ 1.0.0   โ”‚ cluster โ”‚ 56935    โ”‚ 27s    โ”‚ 0    โ”‚ online   โ”‚ 0.3%     โ”‚ 33.2mb   โ”‚ yuxโ€ฆ โ”‚ enabled  โ”‚
โ””โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

ๅ…ณไบŽ่ฟ็ปด

  • ๆœๅŠกๅ™จ่ฟ็ปด๏ผŒๆœ‰ไธ“ไธš็š„OPไบบๅ‘˜ๆฅๅค„็†
  • ๅคงๅ…ฌๅธๆœ‰่‡ชๅทฑ็š„่ฟ็ปด
  • ไธญๅฐๅž‹ๅ…ฌๅธ๏ผŒๆŽจ่ไฝฟ็”จ้˜ฟ้‡Œไบ‘็ญ‰ไบ‘ๆœๅŠก

About

Node + Express/Koa2 + PM2 +Redis

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors