Node学习笔记

前情提要

  • 本篇博客整理内容都是本人在学习node过程中所遇到重要知识点,作用如下:
    • 为初学者整理出学习node过程中会遇到的知识点,有针对性的快速定位知识点
    • 方便有基础者快速查找重点知识,回忆不清晰的知识点

开发环境

Node 6.9.1
Express 4.15.3
Mongoose 4.10.5
Window 10
ubuntu 16.04(服务器环境)

要点整理

全局安装npm包目录(如:cnpm install xxx -g)

  • C:\Users\Think\AppData\Roaming\npm\node_modules(本人电脑)

Node 版本切换

  • 安装过n和nvmw,出现过各种各样的问题,都没有实现正常切换node版本的目的
  • 最后在淘宝镜像下载多个node版本(下载压缩包,这样可以共存多个版本),手动的改变环境变量,来达到切换node版本的目的
  • 阿里云购买的服务器(linux版本:ubuntu 16.04)上安装nvm成功

Windows下通过nvmw安装NodeJS v4.4.0的问题及解决办法

telnet 命令必须在cmd中才能生效

Win10正式版telnet不是内部或外部命令怎么办 [1]

Content-Length 设置

  • var http = require('http');
    
    var server = http.createServer(function(req, res) {
        var body = '你好';
        res.writeHead(200, {
            'Content-Type': 'text/plain;charset=utf8',
            'Content-Length': Buffer.byteLength(body),// 这个值可以<=Buffer.byteLength(body)
        })
        res.end(body);
    })
    
    server.listen(3000, function() {
        console.log('server...')
    })

curl 命令

  • 使用 git bash 可以直接运行 curl 命令
  • curl -X DELETE 127.0.0.1:3000 表示发送一个删除请求

curl命令详解

表单提交模拟 REST 架构

> [REST架构中的PUT、DELETE请求如何实现?](https://segmentfault.com/q/1010000000123615)
> [AJAX如何实现PUT和DELETE方法](https://segmentfault.com/q/1010000002581227)
> [method-override(改写前端form表单的请求)](https://github.com/expressjs/method-override)

Buffer.from() 在 node6.x 中才能使用

Getting TypeError: this is not a typed array using Buffer.from in mocha

参数解析

  • req.body

    • 表单提交的数据
    • 服务端

      ...
      var bodyParser = require('body-parser')
      app.use(bodyParser.json())
      ...
      
      app.all('/list', function(req, res, next) {
          console.log(req.body)
      })
    • 客户端(下例使用FormData提交数据,或者你可以使用原生表单submit提交,不推荐)

      var formData = new FormData();
      formData.append('id', 1);
      
      $.ajax({
          type: 'post',
          url: '/list',
          data: formData,
          contentType: false,
          processData: false,
      })
  • req.query

    • url中?后面带的参数
    • 服务端

      app.all('/list', function(req, res, next) {
          console.log(req.query)
      })
    • 客户端

      $.ajax({
          url: '/list?id=1',
      })
  • req.params

    • rest风格时,url中路径参数
    • 服务端

      app.get('/list/:id', function(req, res, next) {
          console.log(req.params)
      })
    • 客户端

      $.ajax({
          url: '/list/1',
      })
  • req.files

    • 表单提交的数据()
    • 服务端

      ...
      var multer = require('multer')
      var upload = multer({dest: './uploads'})
      ...
      
      app.all('/add', upload.fields([
              {name: 'file'},
          ]), function(req, res, next) {
          console.log(req.files)
      })
    • 客户端(下例使用FormData提交数据,或者你可以使用原生表单submit提交,不推荐)

      var formData = new FormData();
      formData.append('file', document.querySelector('[type=file]').files[0]);
      
      $.ajax({
          type: 'post',
          url: '/add',
          data: formData,
          contentType: false,
          processData: false,
      })

解析url参数 querystring.parse(url.parse(req.url).query)

process.env.NODE_ENV

  • cmd 中 SET NODE_ENV=prod
  • git bash 中
    • 直接运行NODE_ENV=prod node app
    • 或者先运行export NODE_ENV=prod,再运行node app

process.env.NODE_ENV is undefined

connect 中间件

  • 常规处理中间件函数有3个参数:req、res、next,错误处理中间件函数必须接收4个参数:err、req、res、next
  • 调用next()的时候,如果向里面传递参数,如:next(new Error('not found')),那么它接下来会自动寻找错误处理中间件
  • 以下中间件都独立于connect本身
    • cnpm install cookie-parser –save
    • cnpm install body-parser –save
  • connect.limit中间件已经整合到body-parser中
var express = require('express')
var cookieParser = require('cookie-parser')
var moment = require('moment')

var app = express()

app.use(cookieParser('sign'))// 设置签名标记

app.all('/', function(req, res) {
    res.cookie('name', 'hvb', {
        expires: new Date(moment().add(30, 's')),
        httpOnly: true,// 仅服务端可访问
    })
    res.cookie('sex', 'male', {signed: true})// 设置签名的cookie(签名≠加密,为了检验客户端cookie是否伪造,以上不设置签名标记,这里就会报错)
    res.cookie('obj', {a: 1, b: 2})// cookie内容为对象
    res.send({message: '/'})
})

app.all('/get', function(req, res) {
    console.log(req.cookies)// 获取所有普通cookie
    console.log(req.signedCookies)// 获取所有签名cookie
    res.send({message: '/get'})
})

app.all('/del', function(req, res) {
    res.clearCookie('name')// 删除cookie,对httpOnly为true的cookie也会生效
    res.send({message: '/get'})
})
...

加密、摘要和签名的区别
express中cookie的使用和cookie-parser的解读
cookie 和 session

npm模块-bcryptjs(密码加密)

  • 建议安装密码加密模块时,不要选用bcrypt模块(安装依赖问题比较多),使用bcryptjs模块即可(API跟bcrypt是一样的,而且不会出现问题)

nodejs中常用加密算法
用户密码以BCrypt加密的方式来防范被破解
密码破解
md5密码加盐
bcryptjs

使用connect-mongo将session存储到数据库

  • 一定要注意如果有2个接口都需要写入session到数据库,那么这2个接口在前端千万不能同时请求,否则,后面的会完全覆盖前面的session,如下图:
    • app.js
      这里写图片描述
    • 数据库数据:
      这里写图片描述
var express = require('express')
var mongoose = require('mongoose')
var session = require('express-session')
var MongoStore = require('connect-mongo')(session)

mongoose.connect('127.0.0.1:27017/foobar')

var app = express()

app.use(session({
    secret: 'sessiontest',
    resave: true,
    saveUninitialized:true,
    store: new MongoStore({
        mongooseConnection: mongoose.connection,
        ttl: 10,// 表示10秒钟后该session过期,如果不设置session过期时间默认为2周(如果关闭了浏览器,那么该session会立即失效,也就说打开浏览器还需要再次登录,但是数据库的相应字段不会被立即删除,如果想实现自动登录,那么需要借助cookie来实现)
    })
}))

// 存储session
app.get('/', function(req, res) {
    // 这里存储session(具体值)到数据库,可以打开数据库查看(客户端是以cookie的方式来存储session(唯一id),字段为connect.sid)
    req.session.user = {
        a: 1,
        b: 2,
    }
    res.send({message: '/'})
})

// 查看session
app.get('/a', function(req, res) {
    console.log(req.session)// 将在这里输出之前存储的session,或者可以打开数据库查看
    res.send({message: '/a'})
})
...

Session会在浏览器关闭后消失吗?
nodesj中 中间件express-session的理解
connect-mongo和mongoose的区别联系
connect-mongo

自动登录

网站的下次自动登录功能的实现方法

npm模块-serve-favicon(设置网站图标)

var express = require('express')
var favicon = require('serve-favicon')
var path = require('path')

var app = express()

app.use(favicon(path.join(__dirname, 'public', 'dog.png')))// 后缀名可以不是ico且设置之后要重启浏览器才能生效
...

npm模块-morgan(请求日志)

var express = require('express')
var moment = require('moment')
var morgan = require('morgan')
var uuid = require('uuid')// node-uuid已合并为uuid
var path = require('path')
var fs = require('fs')

var app = express()

// 添加唯一标识
morgan.token('id', function(req) {
    return req.id
})
function assignId (req, res, next) {
    req.id = uuid.v4()
    next()
}

// 自定义时间格式
morgan.token('date', function(req) {
    return req.date
})
function assignDate (req, res, next) {
    req.date = moment().format('YYYY-MM-DD HH:mm:ss')// 2017-06-16 17:43:24 
    next()
}

// 创建可写流
var testLogStream = fs.createWriteStream(path.join(__dirname, 'test.log'))

app.use(assignId)
app.use(assignDate)
app.use(morgan(':id :method :url :response-time ms :date\\r', {stream: testLogStream}))// 以自定义的格式写入到test.log,结尾换行
...

Express的日志模块morgan
Java写到.txt文件,如何实现换行
生成唯一标识 uuid

npm模块-compression(gzip)

  • 图片使用gzip后体积反而会变大,所以compression没有对图片进行压缩

npm模块-csurf(防止csrf攻击)

  • server.js

    var express = require('express')
    var cookieParser = require('cookie-parser')
    var bodyParser = require('body-parser')
    var csrf = require('csurf')
    
    var app = express()
    
    app.set('views', './views')
    app.set('view engine', 'ejs')
    
    app.use(express.static('./public'))
    app.use(bodyParser.urlencoded({ extended: false }))
    app.use(cookieParser())
    app.use(csrf({
        cookie: true,
        //ignoreMethods: ['GET', 'HEAD', 'OPTIONS'],// 以上3种方法默认不会进行安全验证,所以注意不要把更新、删除操作使用get请求接收
    }))
    // 自定义错误信息
    app.use(function (err, req, res, next) {
      if (err.code !== 'EBADCSRFTOKEN') return next(err)
    
      res.status(403)
      res.send({message: '非法请求'})
    })
    
    // 渲染模板
    app.all('/', function (req, res) {
      res.render('nav', {csrfToken: req.csrfToken()})
    })
    // 默认不对get请求进行验证,所以即使客户端传来错误的_csrf,也会成功返回
    app.get('/a', function (req, res) {
        res.send({message: '/a'})
    })
    // 会进行验证
    app.post('/b', function (req, res) {
        res.send({message: '/b'})
    })
    ...
  • test.ejs

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test</title>
        <script src="js/jquery-1.11.3.min.js"></script>
    </head>
    <body>
        <form>
            <input type="hidden" name="_csrf" value="<%= csrfToken %>2321312312">
            <input type="text" name="username">
        </form>
        <button class="get">get请求</button>
        <button class="post">post请求</button>
    </body>
    <script>
    $(function() {
        // 发送get请求
        $('.get').on('click', function() {
            $.ajax({
                url: '/a',
                data: $("form").serialize(),
            })
        })
        // 发送post请求
        $('.post').on('click', function() {
            $.ajax({
                url: '/b',
                data: $("form").serialize(),
                type: 'post',
            })
        })
    })
    </script>
    </html>
    

浅谈CSRF攻击方式
npm模块csurf(防止csrf攻击)
为什么http用的时候不能用POST方式替代全部的GET方式?

npm模块-serve-index(生成静态资源目录)

var express = require('express')
var serveIndex = require('serve-index')

var app = express()

app.use('/dir', express.static('./public'))// 托管静态资源
app.use('/dir', serveIndex('./public', {'icons': true}))// 生成静态资源目录

app.all('/', function (req, res) {
  res.send({message: '/'})
})

app.listen(3000, function() {
    console.log('server...')
})

客户端访问http://127.0.0.1:3000/dir即可看到效果

npm模块-connect-flash(携带一些信息给重定向后的页面)

var express = require('express')
var flash = require('connect-flash')

var app = express()

app.use(flash())

app.get('/', function(req, res) {
    res.send({message: req.flash()})// 访问'/a'时会重定向到'/',且页面显示出从'/a'带来的信息,该信息只显示一次,再次刷新'/'页面,就不会有了
})

app.get('/a', function(req, res) {
    req.flash('name', 'hvb')// 携带信息name
    req.flash('age', 1, 2, 3)// 携带信息age
    res.redirect('/')// 重定向到'/'
})
...

客户端访问http://127.0.0.1:3000/a即可看到效果

npm模块-fs-extra(对fs模块的扩展)

  • 可以实现递归删除文件夹、递归创建文件夹
  • 还支持promise方式调用
  • 示例

    var fs = require('fs-extra')
    
    fs.ensureDir('./a/b/c')
    .then(function() {
        console.log('done')
    })
    .catch(function(e) {
        console.log(e.message)
    })

node 模块 fs-extra

npm模块-validator(各种验证)

var validator = require('validator')

console.log(validator.equals('vcxiaohan', 'vcxiaohan'))// 验证2个字符串是否相等(如果都传空,也返回true)
console.log(validator.isAlphanumeric('vcxiaohan'))// 验证是否只包含字母和数字
console.log(validator.isByteLength('vcxiaohan', {min: 4, max: 12}))// 验证字符串的长度是否在4-12之间
console.log(validator.isURL('http://v35new.faqrobot.org/web/common/index.html#material/menuList'))// 验证网址
console.log(validator.isMobilePhone('+8618752011111', 'zh-CN'))// 验证电话(不能验证固定电话)
console.log(validator.isEmail('vcxiaohan@foxmail.com'))// 验证邮箱

nodejs的后端字符串验证器-validator
手机号码前 +86和86的区别
最强正则表达式

npm模块-@fnando/password_strength(验证密码强度)

var PasswordStrength = require('@fnando/password_strength')

var strength = PasswordStrength.test('vcxiaohan', '10hvb29@')// 分别传入用户名和密码,会检测用户名和密码是否相同,若相同,那么强度很低
console.log(strength.isWeak())// false
console.log(strength.isGood())// false
console.log(strength.isStrong())// true
console.log(strength.isValid('good'))// true(我们使用这个方法就可以验证密码强度是否满足需要了)
console.log(strength.isGood() == strength.isValid('good'))// false(注意区别)

@fnando/password_strength

验证重复用户名

  • 如果要改变索引,最好删除数据库且重启服务(因为索引已经建立好了),否则有可能出现改变索引不生效的情况
...
// 定义 Schema
var userSchema = new Schema({
    name: {
        type: String,
        unique: true,// 建立唯一索引
        sparse: true,// 建立稀疏索引(允许值为null的字段同时存在)
    },
})

var User = mongoose.model('User', userSchema)

var app = express()

app.get('/addUser', function(req, res) {
    Blog.create({name: '1234'}).then(function(data) {
        res.send({message: '创建用户成功'})
    }).catch(function(e) {
        console.log(e.message)
        if(e.message.indexOf('E11000 duplicate key')+1) {// 当设为唯一索引的字段有重复时,会报出此错误
            res.send({message: '用户名重复'})
        }else {
            res.send({message: '其他错误'})
        }
    })
})
...

解决MongoDB唯一索引的空值问题

打印对象到控制台

var foo = function() {
    console.log(1)
}
console.log(foo)// 打印出[Function],很不明显
console.log(foo.toString())// 详细的打印出函数内容

Express 4.x

Express 4.x API 英文手册
Express 4.x API 中文手册
Express4.X中的bin/www是作什么用的?为什么没有后缀?
Express Migrating from 3.x to 4.x
nodejs取参四种方法req.body,req.params,req.param,req.body
What is the difference between res.end() and res.send()?
前端ajax,后端res.redirect重定向

body-parser(请求参数解析)

bodyParser中间件的研究
问一个bodyParser获取不到对象参数的问题
bodyParser.urlencoded({extended: true})

模板引擎

EJS 模板快速入门

文件上传 [#f]

multer 中文文档

文件下载

  • 前端千万不要使用ajax请求,否则不会激活下载功能
  • 前端调用下载接口
    • <img src="/download/img">这样服务端返回的图片可以直接显示在页面中
    • <a href="/download/file" target="_blank">点击下载</a>这样用户点击链接后,会直接下载此文件

Content-disposition中Attachment和inline的区别
File not downloading express.js res.download
nodejs+express4.X的文件下载
res.download() not working in my case

格式化时间

  • moment().add()(当前时间向后推迟,可用来设置cookie过期时间)
    这里写图片描述
    Moment.js

https

“HTTPS”安全在哪里?
HTTPS是如何保证连接安全:每位Web开发者都应知道的

Promise

大白话讲解Promise(一)
BlueBird VS ES6 promises
BlueBird 官方文档

supervisor(保存文件后自动重启服务)

  • 该模块主要用在开发环境中,只要你对项目进行更改,再保存后,该模块就会自动重启你的项目,省去了手动重启服务的麻烦
  • cnpm -g install supervisor安装supervisor到全局
  • supervisor app启动app.js
  • supervisor -i public app启动app.js,且忽略public文件夹的监视

使用supervisor提高nodejs调试效率

运维与部署

  • mongod操作

    • 本人自定义的一种结构(仅供参考)
      这里写图片描述
    • 配置文件(适用于linux,根据你的需要配置数据库路径、错误日志路径、开启的端口号)

      
      # mongod.conf
      
      
      
      # for documentation of all options, see:
      
      
      #   http://docs.mongodb.org/manual/reference/configuration-options/
      
      
      
      # Where and how to store data.
      
      storage:
        dbPath: /home/vc/data/blog/lib
        journal:
          enabled: true
      
      
      # where to write logging data.
      
      systemLog:
        destination: file
        logAppend: true
        path: /home/vc/data/blog/log/mongod.log
      
      
      # network interfaces
      
      net:
        port: 30001
        bindIp: 127.0.0.1
      
    • 配置文件(适用于window,根据你的需要配置数据库路径、错误日志路径、开启的端口号)

      
      # mongod.conf
      
      
      
      #数据库路径
      
      dbpath=E:\data\blog\lib
      
      
      #日志输出文件路径
      
      logpath=E:\data\blog\log\mongod.log
      
      
      #错误日志采用追加模式
      
      logappend=true
      
      
      #启用日志文件,默认启用
      
      journal=true
      
      
      #这个选项可以过滤掉一些无用的日志信息,若需要调试使用请设置为false
      
      quiet=true
      
      
      #端口号 默认为27017
      
      port=30002
    • sudo mongod -f /home/vc/data/blog/mongod.conf &
      根据配置文件启动(结尾加的&表示在后台运行此服务,这样关闭窗口,服务依然运行)
    • sudo netstat -lanp | grep 30001查看mongod在linux上的30001端口是否启动成功,如下表示已经启动成功
      这里写图片描述
    • sudo kill 15192杀死mongod进程(以便于我们重新启动)
    • 如果启动了多个mongod服务,而我们只需要杀死其中一个,为了防止杀错进程,我们可以去相应的mongod.log里面查看当前的服务对应的pid,再确定是否是需要杀死的进程
      这里写图片描述
  • pm2操作
    • pm2 start app.js千万不能简写成pm2 start app,2个是不一样的
    • pm2 deploy ecosystem.json production setup初始化项目,如果不setup,下一步会报错
    • pm2 deploy ecosystem.json production启动遇到错误:bash: pm2: command not found,则需要使用cnpm install -g pm2命令在git服务器上安装pm2
  • nginx操作
    • 把下载的nginx传到服务器,进入到configure所在目录,执行./configure --prefix=/home/vc/nginx --with-http_ssl_module
      • –prefix=/home/vc/nginx为指定编译的目录为/home/vc/nginx
      • –with-http_ssl_module为使用ssl模块,用来提供https服务
    • /home/vc/nginx/conf/nginx.confnginx配置文件位置
    • make && make install安装nginx
    • sudo /home/vc/nginx/sbin/nginx -t检测配置文件是否正确
    • sudo /home/vc/nginx/sbin/nginx启动
    • sudo /home/vc/nginx/sbin/nginx -s stop停止
    • sudo /home/vc/nginx/sbin/nginx -s reload重启
    • 如遇到nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)nginx: [error] open() "/home/vc/nginx/logs/nginx.pid" failed (2: No such file or directory)
      错误,说明你之前安装的nginx,在没有正常停止nginx服务的情况下,又重新安装了一次
      • sudo fuser -n tcp 80查看nginx所占用的进程,比如:80/tcp: 7811 7812
      • 则使用sudo kill 7811 7812杀死这2个进程,重新启动nginx即可解决以上问题

How can I make nginx support @font-face formats and allow access-control-allow-origin?
nginx 出现413 Request Entity Too Large问题的解决方法
PM2 介绍
Win10怎么修改hosts文件 Win10系统hosts修改不了
NodeJS on Nginx: 使用nginx反向代理处理静态页面
windows下nginx安装、配置与使用
ubuntu16.04 nginx安装
Ubuntu16.04安装mongodb

ssh免密码登录

  • 要特别注意.ssh父目录的权限问题,如:/home/vc/.ssh,则vc文件夹权限应该是755

解决linux中ssh登录Warning:Permanently added (RSA) to the list of known hosts
SSH localhost免密码后依然需要输入密码问题的解决
在oschina上添加SSH公钥

git管理

  • git init --bare sample.gitgit创建一个裸仓库,裸仓库没有工作区
  • 请一定注意新建的仓库的权限以及所属者,防止本地提交时报错,还不知道是权限不足造成的
  • 先要 获取 git仓库所有分支,才能继续其他操作,否则会报错
  • 有时间我会写一篇搭建git服务及远程连接git服务的文章
  • 使用putty连接git服务
    • 在执行git clone git@116.62.xxx.xx:/home/git/project/sample.git之前,必须要先验证ssh是否接通:ssh git@116.62.xxx.xx
  • 使用sourcetree连接git服务(推荐,可视化界面)
    • 需要注意选用OpenSSH,可以使用任何一对公、私钥进行验证(本地电脑的或者任何一个服务器用户的)
    • 将公钥传到git服务器的/home/git/.ssh/authorized_keys
    • 在sourcetree上选择相对应的私钥
    • 远程地址为git@116.62.xxx.xx:/home/git/project/sample.git

Git远程操作详解
搭建Git服务器

爬虫

SuperAgent中文使用文档
用node爬数据遇到的charset编码转换问题的解决方案
ajax返回数据成功 却进入error方法
常见的反爬虫和应对方法

发送邮件验证

  • 请注意一定要在本地或服务器上使用Node.js v6+,之前我用pm2在服务器部署nodemailer项目不成功,就是node版本太低了

node.js使用nodemailer发送邮件实例

图片处理(图片水印、图片验证码、头像裁剪)

node图片处理工具gm的使用:图片水印、图片验证码、图片裁剪示例

视频处理

  • 转换视频格式
  • 制作视频缩略图
  • 多视频合成一个
  • 监听任务进度

    var ffmpeg = require('fluent-ffmpeg')
    
    ffmpeg(...)
    .on('progress', function(progress) {
        console.log(progress.percent)
    })

fluent-ffmpeg/node-fluent-ffmpeg
FFmpeg安装(windows环境)
Merge Multiple Videos using node fluent ffmpeg

定时任务


  • '* * * * * *'每秒钟执行一次
  • '*/30 * * * * *'每隔30秒执行一次
  • '0 */5 * * * *''*/5 * * * *'秒数可以省略,所以以上都是每隔5分钟执行一次
  • '30 */5 * * * *'每隔5分钟30秒执行一次
  • '0 */5 * * *'每隔5小时执行一次
  • '* 14 * * *'每天的14点开始,每隔1分钟执行一次,直到15点为止
  • 以此类推…

Nodejs学习笔记(十二)— 定时任务(node-schedule)

权限控制

node权限控制模块node_acl的应用

全文检索

node全文检索研究

jsonp(解决跨域问题)

  • 跨域环境:本地协议打开html文件,则会使用file://调用http://127.0.0.1:3002的接口,可构成跨域调用
  • index.html(在本地打开)

    ...
    <script>
        $(function() {
            $.ajax({
                url: 'http://127.0.0.1:3002/jsonp',
                dataType: 'jsonp',// 这句不写的时候,相当于同域名发送xhr,写的时候,相当于不同域名发送jsonp
            })
            .then(function(data) {
                console.log(data)
            })
        })
    </script>
    ...
  • app.js

    app.all('/jsonp', (req, res, next) => {
        res.jsonp({message: 'jsonp...'})// 既可以响应xhr请求,又可以响应jsonp请求
    })

直播

  • 选用七牛直播云服务,按照控制台快速入门配置好直播服务,获取推流地址和播放地址
  • 使用OBS Studio配置好推流地址,进行推流
  • 使用Video.js配置好播放地址,进行播放

PC端播放rtmp和hls视频流
videojs播放不了提示 (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this video.

日志记录+配置环境

  • (new Image()).src = 'http://xxx/xxx'通过这种方式可以很方便的调用一个接口来实现错误日志的记录
  • pm2自带错误日志,运行pm2 logs blog可以展示blog项目的错误日志,该日志包括编写错误bug等,很方便的可以快速定位到项目运行失败的问题
  • 开发阶段:node app直接运行app.js,运行后因为没有配置环境,所以默认是development
  • 生产阶段:pm2 deploy ecosystem.json production使用pm2部署服务,部署成功后,环境是production
  • 在不同的环境下加载不同的日志配置
  • 配置文件目录
    这里写图片描述
  • default.js

    module.exports = {
        logger: require('tracer').colorConsole(),// 日志记录
    }
  • production.js

    module.exports = {
        logger: require('tracer').dailyfile({root:'./logs', allLogsFileName: 'all'}),// 日志记录
    }
  • 效果:开发环境日志会打印到命令面板上,生产环境日志会写入文件中
  • 进阶:可以添加一个日志中间件,这样每次请求信息都可以被记录下来

baryon/tracer
lorenwest/node-config

单元测试


  • 疑问:为什么需要单元测试?平时写项目,开发环境跑起来,各种流程走一遍,保证不出bug不就行了吗?
  • 写成测试用例可以很方便的每次运行,否则比较麻烦

Node.js 单元测试:我要写测试
测试框架 Mocha 实例教程
代码覆盖率工具 Istanbul 入门教程

多线程(child_process/cluster模块)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值