zoukankan      html  css  js  c++  java
  • node.js入门基础

    内容:

    1.node.js介绍

    2.node.js内置常用模块

    3.node.js数据交互

    一、node.js介绍

    (1)node.js特点

    与其他语言相比,有以下优点:

    • 对象、语法和JavaScript一模一样,易于前端使用
    • 相比PHP、Java、python,性能还可以
    • 前后端配合方便
    • 非阻塞、异步的交互

    当然,也有缺点:比如说库支持不如Java丰富,和js一样是单线程单进程

    (2)node.js安装

    下载对应你系统的Node.js版本:https://nodejs.org/en/download/,选安装目录进行安装即可
    安装完毕测试如下:

    (3)node.js用处

    • 服务器 - 小型后台系统、中间层
    • 做工具(测试、构建、抓取) - grunt、gulp、WebPack 

    (4)运行node

    创建一个node文件夹,然后在文件夹下写入1.js:

    1 let a = 12;
    2 let b = 5;
    3 
    4 console.log(a+b)

    然后在命令行中进入node目录下运行该文件:node 1.js  注:node运行文件:node  xxx.js

    运行结果如下:

     

    二、node.js内置常用模块

    1.断言——assert

     1 const assert = require("assert")
     2 
     3 function sum(a, b){
     4     // assert(判断, "xxx")  判断为假输出后面的信息
     5     assert(arguments.length==2, "必须传两个参数")
     6     assert(typeof a == 'number', "第一个参数必须是数字")
     7     assert(typeof b == 'number', "第二个参数必须是数字")
     8     
     9     return a+b
    10 }
    11 
    12 console.log(sum(2, 5))
    13 // 执行下面人任意一句将报错:
    14 // console.log(sum(2, '1'))
    15 // console.log(sum(3))


    2.Buffer和File System模块

    • buffer:曾经是node中的模块,后来融入到node本身之中了,处理二进制
    • file system:处理文件(读写文件)

    file system使用实例:

     1 const fs = require("fs")
     2 
     3 // 读取文件
     4 fs.readFile('1.txt', function(err, data){
     5     if(err){
     6         console.log("有错!");
     7     } else {
     8         console.log(data);
     9         console.log(data.toString());
    10     }
    11     
    12 })  
    13 
    14 // 写文件
    15 fs.writeFile('2.txt', 'xxx', function(err){
    16     if (err) {
    17         console.log(err);
    18     } else {
    19         console.log("成功!");
    20     }
    21 })

    注意:图片不要将二进制转成字符串,这样做会导致图片格式丢失

    获取文件详细信息:

     1 const fs = require('fs')
     2 
     3 fs.stat('1.txt', function (err, stat) {
     4     if(err){
     5         console.log('获取文件信息失败')
     6     } else{
     7         console.log(stat)                           // detail info
     8         console.log(stat.mtime.toGMTString())       // 修改时间
     9     }
    10 })

    Buffer基础使用:

    1 let a = new Buffer('abc');
    2 let b = new Buffer('ddd');
    3 console.log(a, b)
    4 // <Buffer 61 62 63> <Buffer 64 64 64>
    5 
    6 let c = Buffer.concat([a, b]);
    7 console.log(c);
    8 // <Buffer 61 62 63 64 64 64>

    Buffer数据操作:

     1 // 查找
     2 let a=new Buffer('abccc-=-dddder-=-qwerqwer');
     3 console.log(a.indexOf('-=-'));
     4 
     5 // 截取
     6 let b=new Buffer('abccc-=-dddder-=-qwerqwer');
     7 console.log(b.slice(0, 5).toString());
     8 
     9 // 切分  -->  目前buffer自带的操作中没有可以直接用的split
    10 let c=new Buffer('abccc-=-dddder-=-qwerqwer');
    11 
    12 Buffer.prototype.split=Buffer.prototype.split||function (c){        // 如果buffer有split就用buffer自带的split,没有就用下面的函数
    13     let arr=[];
    14 
    15     let cur=0;
    16     let n=0;
    17     while((n=this.indexOf(c, cur))!==-1){
    18         arr.push(this.slice(cur, n));
    19         cur=n+c.length;
    20     }
    21 
    22     arr.push(this.slice(cur));
    23 
    24     return arr;
    25 };
    26 
    27 let arr=c.split('-=-');
    28 console.log(arr);
    29 console.log(arr.map(buffer=>buffer.toString()));

    3.C++ Addons - 用C语言/C++写插件给node用

    4.多进程

    理论上JavaScript是单进程单线程的,可以通过以下模块实现多进程:

    • Child Processes
    • Cluster
    • Process 

    注:node中没有多线程的直接实现(为了考虑安全性、应用性)

    (1)进程与线程

    • 进程:进程拥有独立的执行空间和存储空间
    • 线程:同一个进程内的所有线程共享一套空间、代码
    • 多进程:成本高(慢)、安全(进程间隔离)、进程间通信麻烦、写代码简单、PHP、node
    • 多线程:成本低(快)、不安全(线程间共享)、线程间通信简单、写代码复杂、Java、C
    • 多进程:慢、简单、安全
    • 多线程:快、复杂、脆弱

    (2)进程之间的通信方法

    • 管道
    • 共享内存
    • socket

    (3)详细用法

    详细用法见:https://www.cnblogs.com/wyb666/p/9704056.html


    5.Crypto——散列、签名
    crypto模块提供了md5、sha算法,主要用来进行加密(实质上是散列)、签名

    普通加密:

    1 const crypto = require('crypto')
    2 
    3 let obj = crypto.createHash('sha1')
    4 // 或者用md5加密:
    5 // let obj = crypto.createHash('md5')
    6 
    7 obj.update('123456')
    8 
    9 console.log(obj.digest('hex'))  # 以16进制输出数据

    二次加密并加盐:

     1 const crypto = require('crypto')
     2 
     3 function md5(str){
     4     let obj = crypto.createHash('md5')
     5     obj.update(str)
     6 
     7     return obj.digest('hex')
     8 }
     9 
    10 // 二级加密并加盐
    11 console.log(md5(md5('123456') + 'asdfghjklzxcvbnm,./' ))


    6.http

    • HTTP/HTTPS
    • HTTP/2

    下面是用http模块搭建简单服务器的大致过程:

    最简单的服务器:

     1 const http = require("http")
     2 
     3 let server = http.createServer(function(req, res){
     4     // 路由处理
     5     switch(req.url){
     6         case '/aaa':
     7           res.write('abc');
     8           break;
     9         case '/bbb':
    10           res.write('dddd');
    11           break;
    12         case '/1.html':
    13           res.write('<html><head></head><body>sdfasfasf</body></html>');
    14           break;
    15     }
    16     res.end()
    17 });
    18 
    19 // 监听
    20 server.listen(8080)

    前后端代码分离的服务器(前端代码存在www文件夹下):

     1 const http=require('http');
     2 const fs=require('fs');
     3 
     4 let server=http.createServer(function(req, res){
     5   fs.readFile(`www${req.url}`, function(err, data){
     6     if(err){
     7       res.write('404');     // 404页面
     8     }else{
     9       res.write(data);
    10     }
    11     res.end();
    12   });
    13 });
    14 
    15 server.listen(8080);

    注意:fs.readFile是一个异步操作,必须将res.end()放在readFile内,如果放在readFile外面会导致以下错误:

    这个错误是因为程序不会等readFile执行完就会执行后面的end,因此要将end放在readFile内才会在读完文件后执行end

    7.OS和Path

    • OS:系统相关
    • Path:处理路径
     1 const os=require('os');
     2 const path=require('path');
     3 
     4 // 输出CPU信息:
     5 console.log(os.cpus());
     6 
     7 // 路径相关:
     8 let str='/var/local/www/aaa/1.png';
     9 //dirname  -> 文件夹路径
    10 //basename -> 文件名
    11 //extname  -> 拓展名
    12 console.log(path.dirname(str));   // /var/local/www/aaa
    13 console.log(path.basename(str));  // 1.png
    14 console.log(path.extname(str));   // .png


    8.Events事件队列

    (1)机制原理

    Nodejs的大部分核心API都是基于异步事件驱动设计的,所有可以分发事件的对象都是EventEmitter类的实例。

    大家知道,由于nodejs是单线程运行的,所以nodejs需要借助事件轮询,不断去查询事件队列中的事件消息,然后执行该事件对应的回调函数,有点类似windows的消息映射机制

    (2)使用实例

     1 const Event = require("events").EventEmitter
     2 
     3 let ev = new Event()
     4 
     5 // 1、监听(接受)
     6 ev.on('msg', function(a, b, c){
     7     console.log('收到了msg事件', a, b, c);
     8 })
     9 
    10 // 2、派发(发送)
    11 ev.emit('msg', 12, 5, 98)

    (3)注意

    大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类

    这样做的原因有以下两点:
    • 具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法
    • JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系
    Events(事件)模块是Node.js的核心,许多其他模块用它来围绕着事件架构功能。由于Node.js运行在单一的线程中,任何同步代码都是阻塞的,所以如果有长时间运行的代码的话事件循环便会被阻塞。为了有效地使用Node.js编写代码,必须仔细思考自己的变成风格并遵循一些简单的规则

    9.Query Strings和URL
    (1)Query Strings

    Query Strings:查询字符串,url中的?之后的字符串即为Query Strings

    比如www.xxx.com/find?s=k&wd=123中的查询字符串就是 s=k&wd=123

    querystring实例:

    1 const querystring = require("querystring")
    2 
    3 // url: www.xxx.com/find?s=k&wd=123
    4 let obj = querystring.parse("s=k&wd=123")
    5 
    6 console.log(obj)
    7 // 解析结果: { s: 'k', wd: '123' }

    (2)URL

    url模块和querystring模块不同之处:url模块解析整个url,而querystring只能解析url中问号之后的字符串

    实例:

     1 const url = require("url")
     2 
     3 let obj = url.parse("www.xxx.com/find?s=k&wd=123")
     4 
     5 console.log(obj)
     6 /*
     7 输出结果:
     8 Url {
     9   protocol: null,
    10   slashes: null,
    11   auth: null,
    12   host: null,
    13   port: null,
    14   hostname: null,
    15   hash: null,
    16   search: '?s=k&wd=123',
    17   query: 's=k&wd=123',
    18   pathname: 'www.xxx.com/find',
    19   path: 'www.xxx.com/find?s=k&wd=123',
    20   href: 'www.xxx.com/find?s=k&wd=123'
    21 }
    22 */

    注意:也可以像下面一样指定将query也一并解析

     1 const url = require("url")
     2 
     3 let obj = url.parse("www.xxx.com/find?s=k&wd=123", true)
     4 
     5 console.log(obj)
     6 /*
     7 输出结果:
     8 Url {
     9   protocol: null,
    10   slashes: null,
    11   auth: null,
    12   host: null,
    13   port: null,
    14   hostname: null,
    15   hash: null,
    16   search: '?s=k&wd=123',
    17   query: { s: 'k', wd: '123' },
    18   pathname: 'www.xxx.com/find',
    19   path: 'www.xxx.com/find?s=k&wd=123',
    20   href: 'www.xxx.com/find?s=k&wd=123'
    21 }
    22 */

    10.网络相关模块

    • TCP-稳定  ->   Net
    • UDP-快     ->   UDP/Datagram
    • DNS          ->   域名解析相关
    • Domain     ->   域名相关 

    DNS解析实例:

     1 const dns = require("dns")
     2 
     3 dns.resolve("baidu.com", function(err, res){
     4     if(err){
     5         console.log("解析失败")
     6     } else {
     7         console.log(res)
     8     }
     9 
    10 })
    11 
    12 // 结果: [ '220.181.57.216', '123.125.115.110' ]

    11.流操作——Stream

    (1)什么是流

    连续数据都是流:比如说视频流、网络流、文件流、语音流

    (2)Stream具体操作

    读取写入文件:

     1 const fs = require('fs')
     2 
     3 let rs = fs.createReadStream('1.txt')       // 读取流
     4 let ws = fs.createWriteStream('2.txt')      // 写入流
     5 
     6 rs.pipe(ws)
     7 
     8 // 异常处理
     9 rs.on('error', function (error) {
    10     console.log('读取失败!')
    11 })
    12 
    13 // 读取完成 及 写入完成
    14 rs.on('end', function () {
    15     console.log('读取完成!')
    16 })
    17 
    18 ws.on('finish', function () {
    19     console.log('写入完成!')
    20 })

    12.TLS/SSL

    用于加密、安全

    13.ZLIB
    用于压缩 - gz压缩

    zlib模块使用实例:

     1 const zlib = require('zlib')
     2 const fs = require('fs')
     3 
     4 let rs = fs.createReadStream('jQuery.js')
     5 let ws = fs.createWriteStream('jQuery.js.gz')
     6 
     7 let gz = zlib.createGzip()
     8 
     9 rs.pipe(gz).pipe(ws)
    10 
    11 // 异常处理
    12 rs.on('error', function (error) {
    13     console.log('读取失败!')
    14 })
    15 
    16 // 读取完成 及 写入完成
    17 rs.on('end', function () {
    18     console.log('读取完成!')
    19 })
    20 
    21 ws.on('finish', function () {
    22     console.log('写入完成!')
    23 })

    三、node.js数据交互

    web服务器三大任务:返回文件(html、css、图片等)、数据交互(get、post)、数据库,下面的部分将围绕返回文件及数据交互展开

    1.返回文件

    返回文件可以使用node.js中的fs模块,实例如下:

     1 const fs = require("fs")
     2 
     3 fs.readFile('1.txt', function(err, data){
     4     if(err){
     5         console.log("有错!");
     6     } else {
     7         console.log(data);  // 二进制 Buffer -> 可以直接把这样的数据返回给前端(图片只能返回二进制,返回字符串将使图片失效)
     8         console.log(data.toString());
     9     }
    10     
    11 })  

    2.数据交互 - get和post和文件上传

    • get数据:url里面、小于32K
    • post数据:作为body、比较大
    • file数据:form表单的处理、后端的处理

    (1)设置header

    • setHeader()  -->  一般使用这种来设置header(键值对)
    • writeHeader() 
    • write()

    简单设置header:

     1 const http=require('http');
     2 const fs=require('fs');
     3 
     4 let server=http.createServer(function(req, res){
     5   fs.readFile(`www${req.url}`, function(err, data){
     6     if(err){
     7         // 返回404
     8         res.writeHeader(404);           // header
     9         res.write('Not Found');         // body
    10     }else{
    11         res.write(data);
    12     }
    13     res.end();
    14   });
    15 });
    16 
    17 server.listen(8080);

    (2)get数据处理

    get表单:

    1 <form action="http://localhost:8080/aaa" method="get">
    2     用户:<input type="text" name="user" /><br>
    3     密码:<input type="password" name="pass" /><br>
    4     <input type="submit" value="提交">
    5 </form>

    后端node:

     1 const http=require('http')
     2 const url=require('url')
     3 
     4 let server=http.createServer(function(req, res){
     5     let {pathname, query} = url.parse(req.url, true)
     6     console.log(pathname)  // -> /xxx的形式
     7     console.log(query)     // -> { user: 'xxx', pass: 'xxx' }的形式
     8 
     9     res.end()
    10 })
    11 
    12 server.listen(8080)

     

    (3)post数据处理

    post表单(注意get和post请求可以同时提交):

    1 <form action="http://localhost:8080/aaa?id=12&a=55" method="post">
    2     用户:<input type="text" name="user" /><br>
    3     密码:<input type="password" name="pass" /><br>
    4     <input type="submit" value="提交">
    5 </form>

    后端node:

     1 const http=require('http')
     2 const querystring=require('querystring')
     3 
     4 let server=http.createServer(function(req, res){
     5     let str=''
     6 
     7     // 有一个段到达了
     8     req.on('data', function(data){
     9         str+=data
    10     })
    11 
    12     // 结束了
    13     req.on('end', function(){
    14         let post=querystring.parse(str)
    15         console.log(str)
    16         console.log(post)
    17     })
    18 
    19     res.end()
    20 })
    21 
    22 server.listen(8080)

    注意:url和querystring的不同之处:

     1 // url解析整个url
     2 url.parse("www.xxx.com/aaa/bbb?a=12&b=5")
     3 url.parse("/aaa/bbb?a=12&b=5")
     4 // 另外加上true表示进一步解析query参数(不加就默认不进一步解析query):
     5 url.parse("/aaa/bbb?a=12&b=5", true) 
     6 -> 
     7 {
     8   、、、
     9   "query": {a: 12, b: 5}
    10   、、、
    11 }
    12 
    13 // querystring解析数据
    14 querystring.parse("a=12&b=5")

    (4)get和post数据一块处理

    前端还是使用前面的get表单和post表单

    后端node:

     1 const http=require('http');
     2 const url=require('url');
     3 const querystring=require('querystring');
     4 
     5 let server=http.createServer((req, res)=>{
     6     // GET
     7     let {pathname, query}=url.parse(req.url, true);
     8 
     9     // POST
    10     let str='';
    11     req.on('data', function(data){
    12       str+=data;
    13     });
    14     req.on('end', function(){
    15         let post=querystring.parse(str);
    16 
    17         console.log(pathname, query, post);
    18     });
    19 
    20     res.end()
    21 });
    22 
    23 server.listen(8080);

    注意:在一个表单中可以get请求可以和post请求同时发

    (5)文件上传

    前端代码:

    1 <form action="" method="post" enctype="multipart/form-data">
    2     <input type="file" name="upload-file">
    3     <input type="submit" value="上传文件">
    4 </form>
    5 
    6 注意:
    7     上传文件时表单中的enctype="multipart/form-data"必须要写
    8     input(file)必须要有name

    后端可以使用fs中的readFile和writeFile实现(读取完上传的文件后保存)

    这样做有弊端:

    • 只能等到所有数据都到达了才开始处理
    • readFile先把所有数据全读到内存中,然后回调:
    • 1.极其占用内存
    • 2.资源利用极其不充分

    更好的方法:使用流,实例见后面的文件上传实例

    3.数据交互实例 - 登陆注册简单实现

    (1)基本原理

     1 // GET数据 -> 在url中
     2 let {pathname, query} = url.parse(req.url, true)    // 请求的地址及?之后的参数
     3 
     4 // POST数据 -> 在body里 比较大
     5 let str = ''
     6 req.on('data', function(data){
     7     str += data    // post提交的数据
     8 })
     9 
    10 req.end('end', function(err){
    11     let post = querystring.parse(str)  // 解析提交的数据(字符串->对象)
    12 })

    (2)前端代码

     1 <!-- author: wyb -->
     2 <!DOCTYPE html>
     3 <html lang="en">
     4 <head>
     5     <meta charset="UTF-8">
     6     <title>登陆</title>
     7     <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
     8 </head>
     9 <body>
    10 
    11 用户名: <input type="text" id="user"> <br>
    12 密码: <input type="password" id="pass"> <br>
    13 <input type="button" value="注册" id="btn1">
    14 <input type="button" value="登陆" id="btn2">
    15 
    16 <script>
    17     /*
    18         // 前后端接口:
    19         用户注册:
    20         /reg?user=xxx&pass=xxx
    21         =>{error: 0, msg: '说明'}
    22 
    23         用户登陆:
    24         /login?user=xxx&pass=xxx
    25         =>{error: 0, msg: '说明'}
    26     */
    27     $(function () {
    28         // 注册
    29         $('#btn1').click(function () {
    30             $.ajax({
    31                 url: '/reg',
    32                 data: {user: $('#user').val(), pass: $('#pass').val()},
    33                 dataType: 'json',
    34                 success(data){
    35                     if(data.error){
    36                         alert("错了: " + data.msg)
    37                     } else {
    38                         alert("注册成功")
    39                     }
    40                 },
    41                 error(){
    42                     alert("错了")
    43                 }
    44             })
    45         })
    46 
    47         // 登陆
    48         $('#btn2').click(function () {
    49             $.ajax({
    50                 url: '/login',
    51                 data: {user: $('#user').val(), pass: $('#pass').val()},
    52                 dataType: 'json',
    53                 success(data){
    54                     if(data.error){
    55                         alert("错了: " + data.msg)
    56                     } else {
    57                         alert("登陆成功")
    58                     }
    59                 },
    60                 error(){
    61                     alert("错了")
    62                 }
    63             })
    64         })
    65     })
    66 </script>
    67 
    68 </body>
    69 </html>

    (3)后端代码(node)

     1 const http = require('http');
     2 const url = require('url');
     3 const querystring = require('querystring');
     4 const fs = require('fs');
     5 
     6 /*
     7     // 前后端接口:
     8     用户注册:
     9     /reg?user=xxx&pass=xxx
    10     =>{error: 0, msg: '说明'}
    11 
    12     用户登陆:
    13     /login?user=xxx&pass=xxx
    14     =>{error: 0, msg: '说明'}
    15 */
    16 
    17 // users在内存中保存用户登陆信息
    18 let users = {
    19 //  'xxx': '123456',
    20 //  'wyb': '654321'
    21 };
    22 
    23 let server = http.createServer(function(req, res) {
    24     // GET
    25     let {pathname, query} = url.parse(req.url, true);
    26 
    27     // POST
    28     let str = '';
    29     req.on('data', function (data) {
    30         str += data;
    31     });
    32 
    33     req.on('end', function () {
    34         let post = querystring.parse(str);
    35         let {user, pass} = query
    36 
    37         switch (pathname) {
    38             // 注册
    39             case '/reg':
    40                 if (!user) {
    41                     res.write('{"error": 1, "msg": "user is required!"}')
    42                 } else if (!pass) {
    43                     res.write('{"error": 1, "msg": "pass is required!"}')
    44                 } else if (!/^w{3,32}$/.test(user)) {
    45                     res.write('{"error": 1, "msg": "invalid username!"}')
    46                 } else if (!/^w{6,32}$/.test(pass)) {
    47                     res.write('{"error": 1, "msg": "invalid password!"}')
    48                 } else if (/^['"|]$/.test(pass)) {
    49                     res.write('{"error": 1, "msg": "invalid password!"}')
    50                 } else if (users[user]) {
    51                     res.write('{"error": 1, "msg": "username already exists!"}')
    52                 } else {
    53                     users[user] = pass
    54                     res.write('{"error": 0, "msg": "register success!"}')
    55                 }
    56 
    57                 res.end()
    58                 break
    59             // 登陆
    60             case '/login':
    61                 if (!user) {
    62                     res.write('{"error": 1, "msg": "user is required!"}')
    63                 } else if (!pass) {
    64                     res.write('{"error": 1, "msg": "pass is required!"}')
    65                 } else if (!users[user]) {
    66                     res.write('{"error": 1, "msg": "no this user!"}')
    67                 } else if (users[user]!==pass) {
    68                     res.write('{"error": 1, "msg": "username or password is incorrect!"}')
    69                 } else {
    70                     res.write('{"error": 0, "msg": "login success!"}')
    71                 }
    72 
    73                 res.end()
    74                 break
    75             default:
    76                 fs.readFile(`www${pathname}`, function (err, data) {
    77                     if (err) {
    78                         res.writeHead(404)
    79                         res.write("Not Found!")
    80                     } else {
    81                         res.write(data)
    82                     }
    83 
    84                     res.end()
    85                 })
    86         }
    87 
    88     });
    89 
    90 });
    91 
    92 server.listen(8080);

    4.文件上传实例 - 用流实现

    直接看这里:https://www.cnblogs.com/wyb666/p/9694481.html

  • 相关阅读:
    词频统计
    时事点评-红芯浏览器事件
    我的第一篇博客
    浏览器同源策略,及跨域解决方案
    进击的 JavaScript (八) 之 继承
    进击的 JavaScript (七) 之 原型链
    进击的 JavaScript(五) 之 立即执行函数与闭包
    进击的 JavaScript(六) 之 this
    进击的 JavaScript(四) 之 闭包
    进击的 JavaScript(三) 之 函数执行过程
  • 原文地址:https://www.cnblogs.com/wyb666/p/9635470.html
Copyright © 2011-2022 走看看