全栈课程05&06 Node.js入门

2018-11-01

概述

  • 优势
    • 对象、语法和javascript一样,适于前端使用,但使用习惯不同
    • 前后台配合方便
    • 性能挺优秀(相对phpjavapython
  • 缺点
    • Java有及其丰富的库支持,而Node.js当前的框架、库还不够丰富
  • 用处
    • 服务器:小型后台系统、中间层(使用中间层的目的:两层多一点安全性、性能更高、与前台交互方便)
    • 工具:测试、构建(gruntgulpwebpack)、数据抓取
  • 环境配置
    • 在开发环境通常不需要配置
    • 在生产环境可通过配置文件或环境变量的方式配置版本、数据库等
  • 更多…
    • 关于并发:Node.jsjavascript一样都是单线程、单进程的,优点在于简单;为了提高性能,使用非阻塞的异步交互

常用模块概览

assert

断言,一个应用是函数的参数检查。

let assert = require('assert');
function add(a, b){
    assert(arguments.length == 2, '必须传入两个参数');
    assert(typeof a === 'number', '第一个参数必须是数字');
    assert(typeof b === 'number', '第二个参数必须是数字');
    return a+b;
}
console.log(add(3, '3')); // AssertionError [ERR_ASSERTION]: 第二个参数必须是数字

Buffer、File System

  • Buffer: 用于处理二进制数据
  • File System: 文件系统操作
let fs = require('fs');
// ./1.txt文件内容:am
fs.readFile('./1.txt', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data instanceof Buffer); // true
        console.log(data); // <Buffer 61 6d>
        console.log(data.toString()); // am (注意:不要对非文本执行调用该方法)

        // copy to 2.txt
        fs.writeFile('./2.txt', data, err => {
            if(err){
                console.log(err);
            }else{
                console.log('succeed');
            }
        });
    }
});

C++ Addons

借用该模块可以写些插件,利用C语言极大提高性能。

多进程

js本身是单进程、单线程,通过以下的模块来实现多进程:Child ProcessesClusterProcess

关于进程和线程

  • 进程拥有独立的执行空间、存储;同一个进程内的所有线程共享一套空间、代码
  • 多进程,如PHPNode,慢、简单、安全
    • 成本高(慢)
    • 安全(进程间隔离)
    • 进程间通信麻烦
    • 写代码简单
  • 多线程,如JavaC,快、复杂、脆弱
    • 成本低(快)
    • 不安全(线程要死一块死)
    • 线程间通信容易
    • 写代码复杂

Crypto

用于加密(签名),实现了md5sha常用算法,使用示例:

let crypto = require('crypto');
let obj = crypto.createHash('md5');
obj.update('12');
obj.update('3456');
console.log(obj.digest('hex')); // e10adc3949ba59abbe56e057f20f883e
  • 如何加密才安全?
    • 理论上可以做到100%安全,要求:一次一密,密钥长度>内容长度
    • 目前应用最广泛的加密算法:RSA
  • md5如何破解:md5sha1都是单向散列算法,所谓的破解只是一种暴力手法:记录了一些常见明文的加密值,反向查找。
  • 双层md5md5(md5(明文)+混淆串)

http

HTTP/HTTPS HTTP/2

OS

提供系统信息等,比如:

let os = require('os');
console.log(os.cpus()); // 查看系统CPU信息

Path

路径处理:

let path = require('path');
let str1 = '/a/b/c/r.txt',
    str2 = '/a/b/c/';
console.log(path.basename(str1)); // r.txt
console.log(path.dirname(str1)); // /a/b/c
console.log(path.extname(str1)); // .txt
console.log(path.basename(str2)); // c
console.log(path.dirname(str2)); // /a/b
console.log(path.extname(str2)); // 

Events

事件队列,在async函数之前主要用来处理异步,现在作用减弱。和函数调用的最大区别在于可以解除耦合。

const event = require('events').EventEmitter;
let ev = new event();
// 监听(接收)
ev.on('msg', (a, b, c) => {
    console.log(a+b+c);
});
// 派发(发送)
ev.emit('msg', 1, 2, 5); // 8

Query Strings

let querystring = require('querystring');

let str = 'wd=sd&rsv_spt=1&rsv_iqid=0xed7cab150005e7f5&issp=1&f=3&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=0&rsv_sug3=3&rsv_sug1=1&rsv_sug7=100&prefixsug=sd&rsp=0&inputT=2407&rsv_sug4=2896';

let obj = querystring.parse(str);
console.log(obj);
// {
//     wd: 'sd',
//     rsv_spt: '1',
//     rsv_iqid: '0xed7cab150005e7f5',
//     issp: '1',
//     f: '3',
//     rsv_bp: '0',
//     rsv_idx: '2',
//     ie: 'utf-8',
//     tn: 'baiduhome_pg',
//     rsv_enter: '0',
//     rsv_sug3: '3',
//     rsv_sug1: '1',
//     rsv_sug7: '100',
//     prefixsug: 'sd',
//     rsp: '0',
//     inputT: '2407',
//     rsv_sug4: '2896'
// }

querystring很方便,但是url用得更多。

let url = require('url');

let obj = url.parse('https://www.baidu.com/s?wd=sd&rsv_spt=1&rsv_iqid=0xed7cab150005e7f5&issp=1&f=3&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=0&rsv_sug3=3&rsv_sug1=1&rsv_sug7=100&prefixsug=sd&rsp=0&inputT=2407&rsv_sug4=2896', true);
console.log(obj);
// {
//   protocol: 'https:',
//   slashes: true,
//   auth: null,
//   host: 'www.baidu.com',
//   port: null,
//   hostname: 'www.baidu.com',
//   hash: null,
//   search:
//    '?wd=sd&rsv_spt=1&rsv_iqid=0xed7cab150005e7f5&issp=1&f=3&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=0&rsv_sug3=3&rsv_sug1=1&rsv_sug7=100&prefixsug=sd&rsp=0&inputT=2407&rsv_sug4=2896',
//   query:
//    { wd: 'sd',
//      rsv_spt: '1',
//      rsv_iqid: '0xed7cab150005e7f5',
//      issp: '1',
//      f: '3',
//      rsv_bp: '0',
//      rsv_idx: '2',
//      ie: 'utf-8',
//      tn: 'baiduhome_pg',
//      rsv_enter: '0',
//      rsv_sug3: '3',
//      rsv_sug1: '1',
//      rsv_sug7: '100',
//      prefixsug: 'sd',
//      rsp: '0',
//      inputT: '2407',
//      rsv_sug4: '2896' },
//   pathname: '/s',
//   path:
//    '/s?wd=sd&rsv_spt=1&rsv_iqid=0xed7cab150005e7f5&issp=1&f=3&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=0&rsv_sug3=3&rsv_sug1=1&rsv_sug7=100&prefixsug=sd&rsp=0&inputT=2407&rsv_sug4=2896',
//   href:
//    'https://www.baidu.com/s?wd=sd&rsv_spt=1&rsv_iqid=0xed7cab150005e7f5&issp=1&f=3&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=0&rsv_sug3=3&rsv_sug1=1&rsv_sug7=100&prefixsug=sd&rsp=0&inputT=2407&rsv_sug4=2896' } 

网络

  • TCP-稳定(对用NodeNet)
  • UDP-快(对应NodeUDP/Datagram)

域名解析

DNS,可以通过它向DNS服务器请求将域名解析为IP地址。

let dns = require('dns');

// 请求DNS服务器解析域名,网络操作,异步故需要回调
dns.resolve('baidu.com', (err, data) => {
    if(err){
        console.log(err);
    }else{
        console.log(data);
    }
});

// [ '123.125.115.110', '220.181.57.216' ]

Domain,域名相关处理。

Stream

  • 不是某一模块,是指一种操作——流操作。
  • 连续数据都是流——视频流、网络流、文件流、语音流

TLS/SSL

加密、安全,目前人类常用的加密协议都是靠SSL(安全套接层)实现的。

ZLIB

gz压缩(流)

搭建web服务器

v0.1

const http = require('http');
let server = http.createServer((req, res)=>{
    console.log(req.url);
    res.write('some data');
    res.end();
});
server.listen(8080);
  • node运行js文件:进入目录,运行node 文件名
  • 创建服务器需要使用http模块
  • 一台服务器上通常会运行多个程序,每个程序会监听不同的端口号,外界访问该服务器时需要指定端口号以访问特定的后台程序;一些服务的默认端口号:
    • http: 80
    • ftp: 21
    • mysql: 3306
  • 在一些高级浏览器发现:访问根目录会提交两次请求,额外的一次请求favicon.ico是请求网站图标

v1.0

let http = require('http'),
    fs = require('fs');

let server = http.createServer((req, res) => {
    fs.readFile(`htdocs${req.url}`, (err, data) => {
        if(err){
            console.log(err);
            res.write('404'); // 待改进
        }else{
            res.write(data);
        }
        res.end();
    });
});

server.listen(8080);
console.log('server is listening 8080 ...')

对于前一个版本,无论前端发来的请求路径如何,返回结果总是不变,而且总是200状态码。现在,将所有可以被前端访问的资源文件放在htdocs目录中,当从前端获得请求时,直接以htdocs为更目录,读取相关文件。如果文件存在,则返回给前端,反之则返回404(显然当前这种写法不是真的404)。需要注意res.end()一定要放在回调中。

外话

  • 负载均衡:一个网站可能有多个服务器,尽量让所有用户的请求比较均衡地让各服务器处理。
  • 代理跨域,反向代理
  • ssh是一个基于ssl的协议

(本文完)

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。