node.js入門基礎

內容:css

1.node.js介紹html

2.node.js內置經常使用模塊前端

3.node.js數據交互node

 

 

 

1、node.js介紹python

(1)node.js特色jquery

與其餘語言相比,有如下優勢:web

  • 對象、語法和JavaScript如出一轍,易於前端使用
  • 相比PHP、Java、python,性能還能夠
  • 先後端配合方便
  • 非阻塞、異步的交互

固然,也有缺點:好比說庫支持不如Java豐富,和js同樣是單線程單進程ajax

 

(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

運行結果以下:

 

 

 

2、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)詳細用法

詳細用法見:http://www.javashuo.com/article/p-tnikywxl-bc.html

 


5.Crypto——散列、簽名
crypto模塊提供了md五、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 // 一、監聽(接受)
 6 ev.on('msg', function(a, b, c){
 7     console.log('收到了msg事件', a, b, c);
 8 })
 9 
10 // 二、派發(發送)
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 })

 

 

 

3、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.文件上傳實例 - 用流實現

直接看這裏:http://www.javashuo.com/article/p-khkvyyam-bp.html

相關文章
相關標籤/搜索