Node.js实用知识点

本文介绍如何使用nodejs

简单的HttpServer

创建一个app.js文件输入如下内容
const http = require('http'); http.createServer((req,res) => {
res.writeHead(200, {
'Content-Type': 'text/plain'
}) res.write('Hello, World!\n'); // 返回给客户端的消息 res.end();
}).listen(8000); 用浏览器访问http://localhost:8000/即可

调试nodejs

运行 node --inspect-brk app.js
然后在你的程序里面随便写个断点debugger
使用谷歌访问about://inspect,然后点击inspect进入你的程序
使用前端访问,即可进入刚才打的断点即可

基础路由

  1. 回调函数形式

    const http = require('http');
    
    function index(req, res) {
    res.writeHead(200);
    res.end('Hello, World!');
    } http.createServer(function(req,res){
    res.setHeader("Access-Control-Allow-Origin","*");
    res.setHeader("Access-Control-Allow-Headers","content-type");
    res.setHeader("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS"); if(req.url === '/') {
    return index(req, res);
    } res.writeHead(404);
    res.end(http.STATUS_CODES[404]);
    }).listen(8000)
  2. 对象形式

    const http = require('http');
    var routes = {
    '/': function index(req, res) {
    res.writeHead(200);
    res.end('Hello, World');
    },
    '/test': function test(req, res) {
    res.writeHead(200);
    res.end("test page");
    }
    } http.createServer(function(req,res){
    res.setHeader("Access-Control-Allow-Origin","*");
    res.setHeader("Access-Control-Allow-Headers","content-type");
    res.setHeader("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS"); if(req.url in routes) {
    return routes[req.url](req, res)
    } res.writeHead(404);
    res.end(http.STATUS_CODES[404]);
    }).listen(8000)

nodejs配置开发和生产环境

  1. 项目目录

    Node.js实用知识点

  2. development.js

    module.exports={
    args: {
    a: 'development'
    }
    }
  3. production.js

    module.exports={
    args: {
    a: 'production'
    }
    }
  4. config.js

    var path = require('path');
    var env = process.env.NODE_ENV || 'production';
    env=env.toLowerCase(); var file = path.resolve(__dirname, env); try{
    module.exports = require(file+'.js');
    }catch(err) {
    throw err;
    }
  5. app.js

    const http = require('http');
    
    var args = require('./config/config.js');
    console.log(args.args.a); var routes = {
    '/': function index(req, res) {
    res.writeHead(200);
    res.end('Hello, World');
    },
    '/test': function test(req, res) {
    res.writeHead(200);
    res.end("test page");
    }
    } http.createServer(function(req,res){
    res.setHeader("Access-Control-Allow-Origin","*");
    res.setHeader("Access-Control-Allow-Headers","content-type");
    res.setHeader("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS"); if(req.url in routes) {
    return routes[req.url](req, res)
    } res.writeHead(404);
    res.end(http.STATUS_CODES[404]);
    }).listen(process.env.PORT || 8001)
  6. 运行

    set NODE_ENV=development&&set PORT=8881&&node app.js

nodejs核心模块一览

'assert' 断言测试模块
'buffer' 操作二进制数据
'c/c++_addons' 提供在js中运行c/c++库接口
'child_process' 生成子进程
'cluster' 利用此模块可以把nodejs集群进程部署在同一端口的多核计算机上
'console' 提供一个console功能,类似浏览器的
'crypto' 提供加密功能
'deprecated_apis' 废弃的api
'dns' 通过dns.lookup()访问本机的dns,通过提供的其他api访问网络dns
'domain' 弃用了
'Events' 异步事件驱动架构
'fs' 文件I/O操作
'http' 方便操作http协议
'https' 方便操作https协议
'module' 文件加载系统
'net' 异步网络包装器
'os' 提供操作系统api接口
'path' 提供工具操作文件和文件夹路径
'punycode' 废弃
'querystring' 提供工具转化和格式化URL查询字符串
'readline' 提供接口用来从可读流中读取数据一次一行,例如process.stdin
'repl' 提供一个REPL实现
'stream' 操作流对象
'string_decoder' 提供api用来解码Buffer对象转化成字符串
'timers' 提供全局api用来执行定时任务
'tls_(ssl)' 提供api用来实现OpenSSL
'tracing' 用来追踪程序中产生的信息,添加--trace-events-enabled开启
'tty' 几乎没啥用
'dgram' 提供实现UDP数据报
'url' 提供api操作URL
'util' node.js的内部api
'v8' 提供v8api
'vm' 提供api在v8虚拟环境中编译和运行js
'zlib' 提供实现Gzip的函数接口

express用法

  1. 路由方法处理

    npm install express --save
    
    const express = require('express');
    const app = express();
    const port = 8000; app.all("*",function(req,res,next){
    // 所有路由
    res.header("Access-Control-Allow-Origin","*");
    res.header("Access-Control-Allow-Headers","content-type");
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options') res.send(200);
    else next();
    }); app.get("/testget", function(req, res, next){
    res.send('testget');
    }) app.post("/testpost", function(req, res, next){
    res.send('testpost');
    }) app.put("/testput", function(req, res, next){
    res.send('testput');
    }) app.delete("/testdelete", function(req, res, next){
    res.send('testdelete');
    }) app.use("/testuse", function(req, res, next){
    // 所有路由
    res.send('testuse');
    }) // 路由链
    app.route('/testroute').get(function (req, res, next) {
    res.send('testrouteget');
    }).post(function (req, res, next) {
    res.send('testroutepost');
    }).put(function (req, res, next) {
    res.send('testrouteput');
    }) // 函数链
    app.get('/mypath', function (req, res, next) {
    console.log('1');
    next();
    }, function (req, res, next) {
    console.log('2');
    res.send('....');
    }) app.listen(port, function() {
    console.log('Server listening on http://localhost:' + port);
    });
  2. 模块化(直接传递值)

    app.js
    const express = require('express');
    const otherMiddleware = require('./other.js');
    const app = express(); app.all("*",function(req,res,next){
    // 所有路由
    res.header("Access-Control-Allow-Origin","*");
    res.header("Access-Control-Allow-Headers","content-type");
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options') res.send(200);
    else next();
    }); app.use('/api/v1/', otherMiddleware({ data:'Hello world' })).listen(8000); other.js
    const express = require('express');
    module.exports = function(options={}){
    const router = express.Router(); router.get('/test', (req, res, next) => {
    res.end(options.data);
    }) return router;
    }
  3. 模块化(传递类实例)

    app.js
    const express = require('express');
    const otherMiddleware = require('./other.js');
    const app = express(); app.all("*",function(req,res,next){
    // 所有路由
    res.header("Access-Control-Allow-Origin","*");
    res.header("Access-Control-Allow-Headers","content-type");
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options') res.send(200);
    else next();
    }); class CreateDataService {
    constructor(data='Hello'){
    this.data=data;
    } createData(outdata) {
    return `${this.data}, ${outdata}!`;
    }
    } app
    .use('/api/v1/service1', otherMiddleware({ service: new CreateDataService('Hello')}))
    .use('/api/v1/service2', otherMiddleware({ service: new CreateDataService('Hi')}))
    .listen(8000); other.js
    const express = require('express'); module.exports = function(options={}){
    const router = express.Router(); const {service} = options; router.get('/test', (req, res, next) => {
    res.end(service.createData(req.query.outdata || "haven't any data"));
    }) return router;
    } 请求
    http://localhost:8000/api/v1/service1/test?outdata=World
    http://localhost:8000/api/v1/service2/test?outdata=World
  4. 模板引擎(jade)

    安装 npm install jade --global 
    
    app.js
    const express = require('express');
    const app = express(); const PORT = 8000; app.all("*",function(req,res,next){
    // 所有路由
    res.header("Access-Control-Allow-Origin","*");
    res.header("Access-Control-Allow-Headers","content-type");
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if (req.method.toLowerCase() == 'options') res.send(200);
    else next();
    }); app.set('view engine','jade');
    app.set('views',__dirname); app.get('/', function(req, res) {
    res.render('test');
    }); app.listen(PORT, function(err){
    if(!err) {
    console.log('Server is running at port', PORT);
    }else{
    console.log(JSON.stringify(err));
    }
    }) test.jade
    doctype html
    html
    title hello,jade
    body
    h1 Hello World
    a(href='https://www.baidu.com') baidu
    input(type='text') - var a = 1
    case a
    when 0: p 0
    when 1: p 1
    default: p #{friends} 输入http://localhost:8000/即可看到页面
  5. 模板引擎(ejs)

    npm install ejs
    
    app.js
    const express = require('express');
    const app = express();
    var cors = require('cors');
    const PORT = 8000;
    app.use(cors()); app.set('view engine','ejs');
    app.set('views',__dirname); app.get('/', function(req, res) {
    res.render('test', {
    title: 'ejs测试成功',
    arr: ["a", "b", "c"]
    });
    }); app.listen(PORT, function(err){
    if(!err) {
    console.log('Server is running at port', PORT);
    }else{
    console.log(JSON.stringify(err));
    }
    }) test.ejs
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    </head>
    <body>
    <h1><%= title %></h1> <ul>
    <% for(var i=0; i<arr.length; i++) { %>
    <li>
    <%= arr[i] %>
    </li>
    <% } %>
    </ul>
    </body>
    </html>
  6. 处理json数据

    const express = require('express');
    const app = express();
    var cors = require('cors');
    const PORT = 8000;
    app.use(cors()); app.get('/', function(req, res){
    var info={
    'a': 'aaaa',
    'b': 1111
    } // 方式一 res.json(info);
    // 方式二 res.send(JSON.stringify(info))
    // 方式三 res.status(200).json(info); }) app.listen(PORT, function() {
    console.log('Node.js listening on port ' + PORT)
    })
  7. 请求静态文件

    新建一个public文件夹,在里面放置你的静态文件,比如index.html
    只需要一句代码就搞定一切了 app.use(express.static('public'));
    直接访问http://localhost:8000/index.html即可 你可以添加一个前缀比如 app.use('/static', express.static('public'));
    直接访问 http://localhost:8000/static/index.html
  8. 错误处理

    使用pug模板引擎
    创建一个views文件夹,在里面创建一个error.pug文件,输入如下内容
    html
    body
    h1= message
    h2= error.status
    p= error.stack 测试代码
    app.set('view engine','pug');
    app.set('views',path.resolve(__dirname, 'views')); // 制造一个404错误,并将err抛出
    app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    //pass error to the next matching route.
    next(err);
    });
    // 接收错误,渲染错误页面
    app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
    message: err.message,
    error: err
    });
    });
  9. 从request中获取信息

    最原始的方法获取request属性
    请求路径 /test/11?a=1
    app.get('/test/:id', function(req, res){
    console.log(req.originalUrl); // /test/1?a=1
    console.log(req.params.id); // 11
    console.log(req.query.a); // 1
    res.send(req.get('Content-Type'));
    }) 使用body-parser中间件处理,可以方便地处理请求体的参数
    var bodyParser = require('body-parser');
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: true }));
    app.post('/test', function(req, res, next) {
    console.log(req.body);
    }) 同样何以使用cookie-parser,可以方便地处理cookie对象
    npm install cookie-parser
    var cookieParser = require('cookie-parser')
    app.use(cookieParser());
    app.use(express.static('public'));
    app.get('/setcookie', function(req, res) {
    res.cookie('name', 'yjw', {
    maxAge: 100000, // 过期时间
    httpOnly: true
    });
    return res.send('cookie设置成功');
    });
    app.get('/getcookie', function(req, res) {
    var name = req.cookies['name'];
    if(name) {
    return res.send(name);
    }
    return res.send("cookie中无数据")
    });
  10. 请求之前和完成之后的回调

    在api最前面添加
    app.use(function (req, res, next) {
    function afterResponse() {
    res.removeListener('finish', afterResponse);
    res.removeListener('close', afterResponse);
    // 这里输入请求完成要执行的代码
    console.log("请求完毕");
    }
    res.on('finish', afterResponse);
    res.on('close', afterResponse);
    // 这里输入请求之前要执行的代码
    console.log("准备请求");
    next();
    });
  11. 自定义中间件

    只需要使用app.use传递一个函数即可
    
    app.use(function(req, res, next){
    req.data="testdata";
    next();
    })
  12. Django风格的路由

    实际上就是命名一个路由,然后实现跳转
    npm install express-reverse require('express-reverse')(app);
    app.get('test','/getdata/:data', function(req, res) {
    return res.send(req.params.data);
    }) app.get('/test-redirect', function(req, res, next) {
    res.redirectToRoute('test', { data: 'world' });
    }); 然后请求test-redirect即可

文件I/O

  1. 异步读取文件

    const fs = require('fs');
    const path = require('path');
    app.get('/test', function(req, res) {
    fs.readFile(path.resolve(__dirname, 'test.txt'), {encoding: 'utf-8'}, (err, content) => {
    if(err) return console.error(err);
    res.send(content);
    })
    })
  2. 文件目录

    app.get('/test', function(req, res) {
    fs.readdir(__dirname, (err, files) => {
    if(err) return console.error(err);
    res.send(files.join(' '));
    })
    })
  3. 使用流复制文件

    // highWaterMark是设置缓冲区
    var readable = fs.createReadStream(path.resolve(__dirname, 'test.txt'), { encoding: 'utf8', highWaterMark: 16 * 1024 });
    var writable = fs.createWriteStream(path.resolve(__dirname, 'testbak.txt'));
    readable.pipe(writable);
  4. 检查文件是否有权限

    fs.constants.F_OK 读/写/可执行权限
    fs.constants.R_OK 读权限
    fs.constants.W_OK 写权限
    fs.constants.X_OK 可执行权限 var filepath = path.resolve(__dirname, 'test.txt');
    fs.access(filepath, fs.constants.R_OK | fs.constants.W_OK, (err) => {
    if(err) {
    console.log("%s 文件不存在", filepath);
    }else {
    console.log("可以读或者写 %s 此文件", filepath);
    }
    })
  5. 检查文件和目录是否存在

    var filepath = path.resolve(__dirname, 'test.txt');
    fs.stat(filepath, function(err) {
    if(!err) {
    console.log('文件或者文件夹存在');
    }else if(err.code === 'ENOENT') {
    console.log('文件或者文件夹不存在')
    }
    })
  6. 按行读取

    const readline = require('readline');
    var filepath = path.resolve(__dirname, 'test.txt');
    var linesCount = 0;
    var rl = readline.createInterface({
    input: fs.createReadStream(filepath),
    output: process.stdout,
    terminal: false
    }); rl.on('line', function (line) {
    console.log(line);
    linesCount++;
    });
    rl.on('close', function () {
    console.log(linesCount);
    });
  7. 获取用户输入信息

    const readline = require('readline');
    const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
    });
    rl.question('What is your name?', (name) => {
    console.log(`Hello ${name}!`);
    rl.close();
    });
  8. 创建文件夹

    fs.mkdir(path.resolve(__dirname, 'test'), (err) => {
    if(err && err.code !== 'EEXIST' ? err : null){
    return console.error(err);
    }else {
    // 此处文件夹已经创建成功,可以对刚创建的文件夹做操作 }
    })
  9. 往文件中写数据

    // 直接覆盖
    fs.writeFile(path.resolve(__dirname, 'test.txt'), '我是写入的数据', function(err){
    if(err) return console.error(err);
    });
  10. 文件内容替换

    // 将文件中部分文字替换成其他的文字,其中正则flags的gim分别表示全局、不区分大小写、多行匹配
    var filepath = path.resolve(__dirname, 'test.txt');
    fs.readFile(filepath, 'utf-8', function(err, data) {
    if (err) throw err;
    var newValue = data.replace(/11111111/gim, 'a');
    fs.writeFile(filepath, newValue, 'utf-8', function(err, data) {
    if (err) throw err;
    console.log('搞定!');
    })
    })
  11. 删除文件

    fs.unlink(path.resolve(__dirname, 'test.txt'),function(err){
    if(err) console.error(err);
    console.log("已删");
    })
  12. 使用流读取文件

    let fileBuffer, chunks = [], stream = fs.createReadStream(path.resolve(__dirname, 'test.txt'));
    stream.once('error', (err) => {
    // 出错了就执行此方法
    console.error(err);
    })
    stream.on('data', (chunk) => {
    // 将数据一点点读入到chunks中
    chunks.push(chunk);
    });
    stream.once('end', ()=>{
    // 读取结束后,调用此方法
    fileBuffer = Buffer.concat(chunks);
    console.log(fileBuffer.toString());
    })

nodejs模块

```txt
node自带的模块处理功能
module.exports={ // 只能导出一个对象
a: 'a',
b: 'b'
}
等价写法如下
exports.a='a';
exports.a='b'; 导入模块
const test = require('./test.js'); es6的模块处理 ```

node集群

app.js
const cluster = require('cluster');
const numCPUs = require('os').cpus().length; if (cluster.isMaster) {
// 根据电脑cpu的核心数创建多个Worker分支
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
if (signal) {
console.log(`worker was killed by signal: ${signal}`);
} else if (code !== 0) {
console.log(`worker exited with error code: ${code}`);
} else {
console.log(`worker success ${worker.process.pid} died`);
}
});
} else {
// 让workers共享一个端口
require('./server.js')();
} server.js
// const http = require('http');
const express = require('express');
const app = express();
var cors = require('cors');
app.use(cors());
app.use(express.static('public')); function startServer() {
app.get("/test", function(req, res, next){
res.send('test');
}) app.listen(8000, function() {
console.log('Server listening on http://localhost:' + 8000);
});
}
if (!module.parent) { // 判断此文件是否被其他文件引用
// 这个文件是直接运行的,就直接启动server
startServer();
} else {
// 这个文件是通过其他文件导入执行的,就导出server
module.exports = startServer;
}

事件发射器

const EventEmitter = require('events').EventEmitter;

class Test extends EventEmitter {};
let t = new Test();
t.on('fn', (data) => { // 如果你需要设置一次性的监听器用once
console.log(data);
}) console.log(t.eventNames()); // 查看所有的订阅者(函数)
console.log(t.listenerCount("fn")); // 获取指定监听器的数量 t.emit('fn', "abc");

自动重载

自动刷新代码
npm install -g nodemon
nodemon app.js

环境变量

系统环境变量
console.log(process.env)
命令行参数
console.log(process.argv)
从属性文件中获取配置参数
npm install properties-reader app.js
const path = require('path');
var PropertiesReader = require('properties-reader');
var properties = null;
process.argv.forEach(function (val, index, array) {
var arg = val.split("=");
if (arg.length > 0) {
if (arg[0] === 'env') {
properties = PropertiesReader(path.resolve(__dirname, arg[1] + '.ini'));
}
}
});
var someVal = properties.get('yjw.data.a');
console.log(someVal)
dev.ini
[yjw]
data.a = 1
运行 node app.js env=dev

Promise的简单使用

var fn = function(flag) {
return new Promise(function(resolve, reject) {
if(flag) {
resolve("it is true");
}else {
reject(new Error("it is false"));
}
})
} fn(false).then(function(data){
console.log(data);
}).catch(function(err){
console.log(err);
})

node异常重启

node是单线程的程序,如果node进程出问题了,那么我们开发的程序自然就崩盘了
这个时候可以安装一个监视进程,如果node进程挂了,就再次启动 有n种监视进程,这里就列举一个
forever
npm install forever -g process.on('uncaughtException', function (err) {
console.log(err); process.exit(1); // 捕获node进程异常之后,结束此进程,目的是利用forever重启node,避免数据库不重连
});
forever start index.js // 启动程序
forever list // 产看forever监视进程
forever stop 0 // 停止监视进程

NODE_ENV环境变量

在程序中可以使用process.env.NODE_ENV来辨别当前环境是生产环境还是开发环境
if(process.env.NODE_ENV === 'production') {
} else {
} 设置NODE_ENV的几种方式
方式一:直接设置
set NODE_ENV=development&&node app.js
方式二:.env文件
npm install env-cmd -g
编写.env文件,输入NODE_ENV=development
运行env-cmd .env node app.js即可
方式三:cross-env插件
npm install cross-env -g
cross-env NODE_ENV=development node app.js

异步平行流

多个任务一起执行
var async = require('async'); function fn1(callback) {
setTimeout(function(){
callback(null, 'a') // 第一个参数是错误值,后面的参数都是成功值
}, 100)
} function fn2(callback) {
setTimeout(function(){
callback(null, 'b')
}, 200)
} function fn3(callback) {
setTimeout(function(){
callback(null, 'c')
}, 300)
} async.parallel([ fn1, fn2, fn3 ], function(err, results) {
if (err) {
return console.error(err);
}
console.log(results); // [ 'a', 'b', 'c' ]
});

同步平行流

多个任务一个接一个执行
function fn1(callback) {
setTimeout(function(){
callback(null, 'a')
}, 100)
} function fn2(callback) {
setTimeout(function(){
callback(null, 'b')
}, 200)
} function fn3(callback) {
setTimeout(function(){
callback(null, 'c')
}, 300)
} async.series([ fn1, fn2, fn3 ], function(err, results) {
if (err) {
return console.error(err);
}
console.log(results); // [ 'a', 'b', 'c' ]
});

同步值传递平行流

多个任务一个接一个执行,并且上一个任务的返回值传递给下一个任务

function fn1(callback) {
setTimeout(function(){
callback(null, 'a')
}, 100)
} function fn2(data, callback) {
setTimeout(function(){
callback(null, data+'b')
}, 200)
} function fn3(data, callback) {
setTimeout(function(){
callback(null, data+'c')
}, 300)
} async.waterfall([ fn1, fn2, fn3 ], function(err, results) {
if (err) {
return console.error(err);
}
console.log(results); // abc
});

异步遍历

async.each
async.each(['a', 'b', 'c'], function(item, callback){
console.log(item);
callback(null);
}, function(err){
console.log(err);
})
async.times
长for循环,必须使用这个,要不然你的node程序就卡机了
async.times(5, function(n, next) {
next(null, n);
}, function(err, results) {
console.log(err);
console.log(results); // [ 0, 1, 2, 3, 4 ]
});

使用socket.io实现一个钟表功能

npm install socket.io

服务端代码
const express = require('express');
const app = express();
var cors = require('cors');
app.use(cors()); const server = app.listen(8000, console.log("Socket.io Hello World server started!"));
const io = require('socket.io')(server);
io.on('connection', (socket) => {
console.log("Client connected!");
socket.on('receivefromclient', (msg) => {
console.log(msg);
})
setInterval(function(){
var today=new Date()
var h=today.getHours()
var m=today.getMinutes()
var s=today.getSeconds()
socket.emit('receivefromserver', h+":"+m+":"+s);
}, 1000)
});
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>
</head>
<body>
<p id="message"></p>
</body> <script>
var socket = io("http://localhost:8000");
setInterval(function(){
socket.on("receivefromserver", function(msg) {
document.getElementById('message').innerHTML = msg;
});
}, 1000)
socket.emit('receivefromclient', '收到消息!');
</script> </html>
上一篇:IDEA激活方式(亲测有效)加汉化方式


下一篇:产品激活 比如Windows激活 , office激活 等激活的原理是什么? KMS等激活工具安全吗?