nodejs全棧入門(mén)開(kāi)發(fā)教程

前言

1、nodej是什么?what

2、為什么用? why

3、怎么用?how

一、Nodejs介紹和特色

1、nodejs是什么?

Node.js 不是一門(mén)語(yǔ)言,而是一個(gè)開(kāi)發(fā)平臺(tái)(有對(duì)應(yīng)的語(yǔ)言和實(shí)現(xiàn)特定功能的api),是一個(gè)用C++開(kāi)發(fā)的 ,事件驅(qū)動(dòng) I/O 服務(wù)端 JavaScript 環(huán)境,是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行環(huán)境,V8 引擎執(zhí)行 Javascript 的速度非???,性能非常好,

用于方便地搭建響應(yīng)速度快、易于擴(kuò)展的網(wǎng)絡(luò)應(yīng)用,它有非阻塞、事件驅(qū)動(dòng)模型的特性,有輕量高效的特點(diǎn),適用于分布式設(shè)備上運(yùn)行數(shù)據(jù)密集型的實(shí)時(shí)應(yīng)用

Node.js是一個(gè)用C++開(kāi)發(fā)的 、服務(wù)器端、單阻塞式I/O、事件驅(qū)動(dòng)模型、基于 Chrome V8 引擎的 JaveScript運(yùn)行環(huán)境( 即Javascript 語(yǔ)言解釋器)

2、安裝配置

2.1、node下載地址

https://nodejs.org/en/download/

LTS版本:長(zhǎng)期支持版,即穩(wěn)定版(建議) Current版本:最新版 安裝node后在cmd下運(yùn)行node -v即可查看安裝的node.js版本
node版本png

如果安裝成功卻提示node不是內(nèi)部或者外部的命令。則需要手動(dòng)配置環(huán)境變量

2.2、配置環(huán)境變量

為什么要配置環(huán)境變量:一般情況下,cmd環(huán)境想要運(yùn)行一個(gè)文件,例如node.exe,那么對(duì)應(yīng)的路徑下必須有node.exe這個(gè)文件才能啟動(dòng),否則就會(huì)提示命令不存在。 配置環(huán)境變量就是告訴電腦,如果我們輸入的命令在當(dāng)前路徑下沒(méi)有對(duì)應(yīng)的執(zhí)行文件,那么就去其他路徑下查看,配置環(huán)境變量也就是添加一個(gè)可供查找的絕對(duì)路徑 如何配置環(huán)境變量: 右鍵計(jì)算機(jī)>屬性>系統(tǒng)高級(jí)設(shè)置>高級(jí)>環(huán)境變量

環(huán)境變量png

選擇Path這個(gè)變量名,對(duì)應(yīng)的變量值是有若干的路徑組成的每個(gè)路徑用";"隔開(kāi),添加時(shí)也記得加 分號(hào) ,這里node.js安裝是已經(jīng)自動(dòng)添加了環(huán)境變量,所以里面已經(jīng)有node.js的路徑了,如果沒(méi)有,就要手動(dòng)添加

2.3、node的版本管理工具(nvm)

1.安裝nvm(Node Version Manager )
nvm安裝版png

2.常用命令:cmd窗口輸入命令

  • nvm v:顯示nvm版本,如果有則表示安裝成功。
  • nvm list: 列出已經(jīng)安裝的node.js版本
  • nvm uninstall 版本號(hào):卸載指定版本的nodejs。
  • nvm install latest:安裝最新版node.js
  • nvm install 版本號(hào):安裝指定的node.js版本
  • nvm ues 版本號(hào):使用指定的node.js版本

2.4、自動(dòng)重啟服務(wù)器(node-dev/nodemon/supervisor)

2.4.1、node-dev

1、node-dev是一個(gè)node.js開(kāi)發(fā)工具,當(dāng)文件被修改時(shí),它會(huì)自動(dòng)重新啟動(dòng)node進(jìn)程

// 全局安裝
npm install -g node-dev
// 運(yùn)行服務(wù)
node-dev index.js

2、Node-dev 可以當(dāng)有js文件修改后自動(dòng)去重啟nodejs進(jìn)程, 這樣就不用每次ctrl+c 終止在重啟了,而且不僅支持js文件, .json .node .coffee 文件格式都支持

2.4.2、nodemon

1、 Nodemon是一個(gè)使用工具,它將會(huì)見(jiàn)監(jiān)視源文件中任何的更改并自動(dòng)重啟服務(wù)器

// 全局安裝
npm install -g nodemon
// 運(yùn)行服務(wù)
nodemon index.js

2、實(shí)際項(xiàng)目中可在package.json中配置

{
  "name": "nodejs",
  "version": "1.0.0",
  "description": "nodejs測(cè)試",
  "main": "index.js",
  "dependencies": {},
  "devDependencies": {},
  "scripts": {
    "start": "nodemon index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
2.4.3、npm

1、npm是Node Package Manage的縮寫(xiě),意思是node的包管理系統(tǒng)

  • NPM提供了很多命令,例如installpublish,使用npm help可查看所有命令。
  • 使用npm help <command>可查看某條命令的詳細(xì)幫助,例如npm help install。
  • package.json所在目錄下使用npm install . -g可先在本地安裝當(dāng)前命令行程序,可用于發(fā)布前的本地測(cè)試。
  • 使用npm update <package>可以把當(dāng)前目錄下node_modules子目錄里邊的對(duì)應(yīng)模塊更新至最新版本。
  • 使用npm update <package> -g可以把全局安裝的對(duì)應(yīng)命令行程序更新至最新版。
  • 使用npm cache clear可以清空NPM本地緩存,用于對(duì)付使用相同版本號(hào)發(fā)布新版本代碼的人。
  • 使用npm unpublish <package>@<version>可以撤銷(xiāo)發(fā)布自己發(fā)布過(guò)的某個(gè)版本代碼。

2、使用淘寶鏡像

// 使用淘寶鏡像
npm install -g cnpm --registry=https://registry.npmmirror.com
// 使用cnpm 命令來(lái)安裝模塊
cnpm install [name]

3、yarn

3、Nodejs三大特色

故事背景:

高級(jí)餐廳(傳統(tǒng)服務(wù)器語(yǔ)言):(給每一個(gè)用戶分配一個(gè)服務(wù)員(多個(gè)服務(wù)員,多線程)—>用戶看菜單->等待I/O操作->要點(diǎn)的菜告訴服務(wù)員-> I/O 操作結(jié)束后線程繼續(xù)執(zhí)行->看菜單,服務(wù)員閑置到你點(diǎn)完( I/O 操作結(jié)束) -->阻塞式 I/O

小餐館(nodejs):所有用戶共享一個(gè)服務(wù)員(一個(gè)服務(wù)員,單線程)-->用戶看菜單(等待I/O操作)-->您先看著菜單,點(diǎn)好了叫我(回調(diào)函數(shù))-->顧客點(diǎn)完后會(huì)主動(dòng)叫服務(wù)員(執(zhí)行回調(diào)函數(shù))

3.1. 單線程

3.1.1、和其他后臺(tái)語(yǔ)言不一樣,Node.js 不會(huì)為每一個(gè)客戶建立一個(gè)新的線程。而僅僅使用一個(gè)線程。當(dāng)有用戶鏈接了,就會(huì)出發(fā)一個(gè)內(nèi)部事件,經(jīng)過(guò)非阻塞I/O、事件驅(qū)動(dòng)機(jī)制,讓Node.js程序在宏觀上也是并行的。

服務(wù)器單線程帶來(lái)的好處,操作系統(tǒng)徹底再也不用有線程建立、銷(xiāo)毀的時(shí)間開(kāi)銷(xiāo)。

3.1.2、相對(duì)于php、java后端語(yǔ)言的多線程,nodej采用異步單線程優(yōu)勢(shì)

節(jié)約服務(wù)器內(nèi)存(線程越多占用的內(nèi)存越多) 節(jié)約上下文切換的時(shí)間(由于多線程實(shí)現(xiàn)原理是通過(guò)切換時(shí)間片來(lái)實(shí)現(xiàn)的 所以線程越多 需要切換的次數(shù)就越多 耗費(fèi)的時(shí)間越長(zhǎng)) 不存在鎖的問(wèn)題 (java通常會(huì)通過(guò)給進(jìn)程加鎖來(lái)解決多個(gè)線程訪問(wèn)同一資源的問(wèn)題 而單線程就不存在這個(gè)問(wèn)題)

固然它的優(yōu)點(diǎn)也是它的劣勢(shì),一個(gè)用戶形成了線程的崩潰,整個(gè)服務(wù)也會(huì)崩潰。

3.1.3、瀏覽器線程(了解)

JS引擎線程 .GUI渲染線程(和JS引擎線程互斥 兩者只有一者正在執(zhí)行 不會(huì)同時(shí)進(jìn)行) 事件觸發(fā)線程 定時(shí)器觸發(fā)線程 異步http請(qǐng)求線程

3.2. 非阻塞 I/O(no-blocking I/O)

3.2.1、正常來(lái)講,I/O 阻塞了代碼的執(zhí)行,極大地下降了程序的執(zhí)行效率。因?yàn)?Node.js 采用了非阻塞 I/O 機(jī)制,在執(zhí)行了訪問(wèn)數(shù)據(jù)庫(kù)的代碼以后,將當(dāng)即轉(zhuǎn)而執(zhí)行其后面的代碼,把數(shù)據(jù)庫(kù)返回的處理代碼放到回調(diào)函數(shù)中,從而提升了程序的執(zhí)行效率

3.2.2 理解非阻塞和同步異步

同步和異步起決于被調(diào)用者 阻塞和非阻塞起決于調(diào)用者

阻塞是按順序執(zhí)行的,而非阻塞是不需要按順序的

3.3. 事件驅(qū)動(dòng)(event-driven)

在 Node 中,客戶端請(qǐng)求創(chuàng)建鏈接,提交數(shù)據(jù)等行為,會(huì)觸發(fā)相應(yīng)的事件,在一個(gè)時(shí)刻,只能執(zhí)行一個(gè)事件回調(diào)函數(shù),可是在執(zhí)行一個(gè)事件回調(diào)的中途,能夠轉(zhuǎn)而處理其余事件,而后繼續(xù)執(zhí)行原事件的回調(diào)函數(shù),這種處理機(jī)制,稱為“事件環(huán)”機(jī)制。

Node.js 使用事件驅(qū)動(dòng)模型,當(dāng)web server接收到請(qǐng)求,就把它關(guān)閉然后進(jìn)行處理,然后去服務(wù)下一個(gè)web請(qǐng)求。當(dāng)這個(gè)請(qǐng)求完成,它被放回處理隊(duì)列,當(dāng)?shù)竭_(dá)隊(duì)列開(kāi)頭,這個(gè)結(jié)果被返回給用戶。這個(gè)模型非常高效可擴(kuò)展性非常強(qiáng),因?yàn)?webserver 一直接受請(qǐng)求而不等待任何讀寫(xiě)操作。(這也稱之為非阻塞式IO或者事件驅(qū)動(dòng)IO)在事件驅(qū)動(dòng)模型中,會(huì)生成一個(gè)主循環(huán)來(lái)監(jiān)聽(tīng)事件,當(dāng)檢測(cè)到事件時(shí)觸發(fā)回調(diào)函數(shù)。
[圖片上傳失敗...(image-64461e-1678162204288)]

整個(gè)事件驅(qū)動(dòng)的流程就是這么實(shí)現(xiàn)的,非常簡(jiǎn)潔。有點(diǎn)類(lèi)似于觀察者模式,事件相當(dāng)于一個(gè)主題(Subject),而所有注冊(cè)到這個(gè)事件上的處理函數(shù)相當(dāng)于觀察者

Node.js 有多個(gè)內(nèi)置的事件,我們可以通過(guò)引入 events 模塊,并通過(guò)實(shí)例化 EventEmitter 類(lèi)來(lái)綁定和監(jiān)聽(tīng)事件,如下實(shí)例:

[圖片上傳失敗...(image-effb9d-1678159779170)]

Node.js中所有的I/O都是異步的,回調(diào)函數(shù),套回調(diào)函數(shù)

4、為什么要用Nodejs,優(yōu)勢(shì)

  1. 它是一個(gè)Javascript運(yùn)行環(huán)境(簡(jiǎn)單容易上手)

  2. 依賴于Chrome V8引擎進(jìn)行代碼解釋(號(hào)稱世界上最快的解釋器)

  3. 事件驅(qū)動(dòng)(高并發(fā)處理速度優(yōu)勢(shì))

  4. 非阻塞I/O(創(chuàng)建新的線程去執(zhí)行,不會(huì)阻塞主線程。動(dòng)作并行執(zhí)行,速度更快)--->適合I/O密集型應(yīng)用

  5. 輕量、可伸縮,適于實(shí)時(shí)數(shù)據(jù)交互應(yīng)用(由高并發(fā)特性決定)

  6. 單進(jìn)程,單線程(不會(huì)占用大量的內(nèi)存

  7. 處理高并發(fā)場(chǎng)景性能更佳

  8. node 最大的優(yōu)勢(shì)就是性能強(qiáng),同樣的服務(wù)器性能使用 node 可以比傳統(tǒng)的服務(wù)器語(yǔ)言多容納一百倍的用戶(對(duì)于不同的任務(wù)有不同的差別, I/O 操作越多,node優(yōu)勢(shì)越明顯)(每個(gè)線程2M,理論8g內(nèi)存,就是4000用戶,nodejs就是4萬(wàn))

5、Nodejs劣勢(shì)

1、不適合CPU密集型應(yīng)用;CPU密集型應(yīng)用給Node帶來(lái)的挑戰(zhàn)主要是:由于JavaScript單線程的原因,如果有長(zhǎng)時(shí)間運(yùn)行的計(jì)算(比如大循環(huán)),將會(huì)導(dǎo)致CPU時(shí)間片不能釋放,使得后續(xù)I/O無(wú)法發(fā)起; 解決方案:分解大型運(yùn)算任務(wù)為多個(gè)小任務(wù),使得運(yùn)算能夠適時(shí)釋放,不阻塞I/O調(diào)用的發(fā)起;

2、只支持單核CPU,不能充分利用CPU;

3、可靠性低,一旦代碼某個(gè)環(huán)節(jié)崩潰,整個(gè)系統(tǒng)都崩潰 原因:?jiǎn)芜M(jìn)程,單線程 解決方案: (1)Nnigx反向代理,負(fù)載均衡,開(kāi)多個(gè)進(jìn)程,綁定多個(gè)端口; (2)開(kāi)多個(gè)進(jìn)程監(jiān)聽(tīng)同一個(gè)端口,使用cluster模塊;

4、開(kāi)源組件庫(kù)質(zhì)量參差不齊,更新快,向下不兼容

5、Debug不方便,錯(cuò)誤沒(méi)有stack trace

總結(jié):nodejs本就是極客追求性能極致的產(chǎn)物,缺少了很多服務(wù)器的健壯性考量,所以不適用于銀行、證券、電信等需要極高可靠性的業(yè)務(wù)中

6、應(yīng)用場(chǎng)景

nodeJs 善于I/O,不善于計(jì)算,因?yàn)閚odejs最擅長(zhǎng)的就是任務(wù)調(diào)度,如果你的業(yè)務(wù)有巨量的CPU計(jì)算(同步代碼),實(shí)際上也相當(dāng)于這個(gè)計(jì)算阻塞了整個(gè)線程,即巨量的計(jì)算不適合NodeJS開(kāi)發(fā)。 當(dāng)應(yīng)用程序需要處理大量高并發(fā)的I/O,而在向客戶端發(fā)出響應(yīng)之前,應(yīng)用程序內(nèi)部并不需要復(fù)雜的處理的時(shí)候,NodeJs非常適合。 適合與 web socket 配合,開(kāi)發(fā)長(zhǎng)連接的實(shí)時(shí)交互應(yīng)用程序。

  1. RESTful API

這是NodeJS最理想的應(yīng)用場(chǎng)景,可以處理數(shù)萬(wàn)條連接,本身沒(méi)有太多的邏輯,只需要請(qǐng)求API,組織數(shù)據(jù)進(jìn)行返回即可。它本質(zhì)上只是從某個(gè)數(shù)據(jù)庫(kù)中查找一些值并將它們組成一個(gè)響應(yīng)。由于響應(yīng)是少量文本,入站請(qǐng)求也是少量的文本,因此流量不高,一臺(tái)機(jī)器甚至也可以處理最繁忙的公司的API需求。

  1. 統(tǒng)一Web應(yīng)用的UI層

目前MVC的架構(gòu),在某種意義上來(lái)說(shuō),Web開(kāi)發(fā)有兩個(gè)UI層,一個(gè)是在瀏覽器里面我們最終看到的,另一個(gè)在server端,負(fù)責(zé)生成和拼接頁(yè)面。

不討論這種架構(gòu)是好是壞,但是有另外一種實(shí)踐,面向服務(wù)的架構(gòu),更好的做前后端的依賴分離。如果所有的關(guān)鍵業(yè)務(wù)邏輯都封裝成REST調(diào)用,就意味著在上層只需要考慮如何用這些REST接口構(gòu)建具體的應(yīng)用。那些后端程序員們根本不操心具體數(shù)據(jù)是如何從一個(gè)頁(yè)面?zhèn)鬟f到另一個(gè)頁(yè)面的,他們也不用管用戶數(shù)據(jù)更新是通過(guò)Ajax異步獲取的還是通過(guò)刷新頁(yè)面。

  1. 大量Ajax請(qǐng)求的應(yīng)用

例如個(gè)性化應(yīng)用,每個(gè)用戶看到的頁(yè)面都不一樣,緩存失效,需要在頁(yè)面加載的時(shí)候發(fā)起Ajax請(qǐng)求,NodeJS能響應(yīng)大量的并發(fā)請(qǐng)求?! 】偠灾?,NodeJS適合運(yùn)用在高并發(fā)、I/O密集、少量業(yè)務(wù)邏輯的場(chǎng)景。

4、具體場(chǎng)景可以表現(xiàn)為如下:

  1. Web服務(wù) API 如:REST
  2. 基于web、canvas等多人聯(lián)網(wǎng)游戲
  3. 后端的web服務(wù),如:跨域、服務(wù)器端的請(qǐng)求;
  4. 基于web的多人實(shí)時(shí)聊天客戶端、聊天室、圖文直播
  5. 高并發(fā)量的web應(yīng)用程序 如:用戶表單收集系統(tǒng)、實(shí)時(shí)交互系統(tǒng)、考試系統(tǒng)、聯(lián)網(wǎng)軟件
  6. 單頁(yè)面瀏覽器應(yīng)用程序

二、Nodejs

1、 REPL(交互式解釋器)

Node.js REPL(Read Eval Print Loop:交互式解釋器) 表示一個(gè)電腦的環(huán)境,類(lèi)似 Windows 系統(tǒng)的終端或 Unix/Linux shell,我們可以在終端中輸入命令,并接收系統(tǒng)的響應(yīng)

//啟動(dòng) Node 的終端
node
  • ctrl + c - 退出當(dāng)前終端。
  • ctrl + c 按下兩次 - 退出 Node REPL。
  • ctrl + d - 退出 Node REPL.
  • 向上/向下 鍵 - 查看輸入的歷史命令
  • tab 鍵 - 列出當(dāng)前命令
  • .help - 列出使用命令
  • .break - 退出多行表達(dá)式
  • .clear - 退出多行表達(dá)式
  • .save filename - 保存當(dāng)前的 Node REPL 會(huì)話到指定文件
  • .load filename - 載入當(dāng)前 Node REPL 會(huì)話的文件內(nèi)容。

2、Node.js 全局對(duì)象

2.1、有唯一的全局對(duì)象 global 2.2、process = global.process process也是Node.js提供的一個(gè)對(duì)象,它代表當(dāng)前Node.js進(jìn)程

2.3、判斷JavaScript執(zhí)行環(huán)境

if (typeof(window) === 'undefined') {
    console.log('node.js');
} else {
    console.log('browser');
}

3、事件循環(huán)

ode.js 使用事件驅(qū)動(dòng)模型,當(dāng)web server接收到請(qǐng)求,就把它關(guān)閉然后進(jìn)行處理,然后去服務(wù)下一個(gè)web請(qǐng)求。

當(dāng)這個(gè)請(qǐng)求完成,它被放回處理隊(duì)列,當(dāng)?shù)竭_(dá)隊(duì)列開(kāi)頭,這個(gè)結(jié)果被返回給用戶。

這個(gè)模型非常高效可擴(kuò)展性非常強(qiáng),因?yàn)?webserver 一直接受請(qǐng)求而不等待任何讀寫(xiě)操作。(這也稱之為非阻塞式IO或者事件驅(qū)動(dòng)IO)

在事件驅(qū)動(dòng)模型中,會(huì)生成一個(gè)主循環(huán)來(lái)監(jiān)聽(tīng)事件,當(dāng)檢測(cè)到事件時(shí)觸發(fā)回調(diào)函數(shù)

// 引入 events 模塊
var events = require('events');
// 創(chuàng)建 eventEmitter 對(duì)象
var eventEmitter = new events.EventEmitter();

// 創(chuàng)建事件處理程序
var connectHandler = function connected() {
   console.log('連接成功。');

   // 觸發(fā) data_received 事件 
   eventEmitter.emit('data_received');
}

// 綁定 connection 事件處理程序
eventEmitter.on('connection', connectHandler);

// 使用匿名函數(shù)綁定 data_received 事件
eventEmitter.on('data_received', function(){
   console.log('數(shù)據(jù)接收成功。');
});

// 觸發(fā) connection 事件 
eventEmitter.emit('connection');

console.log("程序執(zhí)行完畢。");

大多數(shù)時(shí)候我們不會(huì)直接使用 EventEmitter,而是在對(duì)象中繼承它。包括 fs、net、 http 在內(nèi)的,只要是支持事件響應(yīng)的核心模塊都是 EventEmitter 的子類(lèi)

4、模塊(ES6 模塊、CommonJS 模塊)

1、語(yǔ)法上面,CommonJS 模塊使用require()加載和module.exports輸出,ES6 模塊使用importexport。

// package.json 文件中,指定type 字段
{
   "type": "module"
}

.mjs文件總是以 ES6 模塊加載,.cjs文件總是以 CommonJS 模塊加載,.js文件的加載取決于package.json里面type字段的設(shè)置

4、fs

Node.js內(nèi)置的fs模塊就是文件系統(tǒng)模塊,負(fù)責(zé)讀寫(xiě)文件。

和所有其它JavaScript模塊不同的是,fs模塊同時(shí)提供了異步和同步的方法

// 異步讀取文件
'use strict';
var fs = require('fs');
fs.readFile('sample.txt', 'utf-8', function (err, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(data);
    }
});

// 同步讀取文件
'use strict';
var fs = require('fs');
var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data)

5、Stream(流)

stream是Node.js提供的又一個(gè)僅在服務(wù)區(qū)端可用的模塊,目的是支持“流”這種數(shù)據(jù)結(jié)構(gòu)

Node.js,Stream 有四種流類(lèi)型:

  • Readable - 可讀操作。
  • Writable - 可寫(xiě)操作。
  • Duplex - 可讀可寫(xiě)操作.
  • Transform - 操作被寫(xiě)入數(shù)據(jù),然后讀出結(jié)果。

所有的 Stream 對(duì)象都是 EventEmitter 的實(shí)例。常用的事件有:

  • data - 當(dāng)有數(shù)據(jù)可讀時(shí)觸發(fā)。

  • end - 沒(méi)有更多的數(shù)據(jù)可讀時(shí)觸發(fā)。

  • error - 在接收和寫(xiě)入過(guò)程中發(fā)生錯(cuò)誤時(shí)觸發(fā)。

  • finish - 所有數(shù)據(jù)已被寫(xiě)入到底層系統(tǒng)時(shí)觸發(fā)。

    文件流讀取文本內(nèi)容的示例

'use strict';

var fs = require('fs');

// 打開(kāi)一個(gè)流:
var rs = fs.createReadStream('sample.txt', 'utf-8');

rs.on('data', function (chunk) {
    console.log('DATA:')
    console.log(chunk);
});

rs.on('end', function () {
    console.log('END');
});

rs.on('error', function (err) {
    console.log('ERROR: ' + err);
});

6、http模塊

request對(duì)象封裝了HTTP請(qǐng)求,我們調(diào)用request對(duì)象的屬性和方法就可以拿到所有HTTP請(qǐng)求的信息;

response對(duì)象封裝了HTTP響應(yīng),我們操作response對(duì)象的方法,就可以把HTTP響應(yīng)返回給瀏覽器。

'use strict';

// 導(dǎo)入http模塊:
var http = require('http');

// 創(chuàng)建http server,并傳入回調(diào)函數(shù):
var server = http.createServer(function (request, response) {
    // 回調(diào)函數(shù)接收request和response對(duì)象,
    // 獲得HTTP請(qǐng)求的method和url:
    console.log(request.method + ': ' + request.url);
    // 將HTTP響應(yīng)200寫(xiě)入response, 同時(shí)設(shè)置Content-Type: text/html:
    response.writeHead(200, {'Content-Type': 'text/html'});
    // 將HTTP響應(yīng)的HTML內(nèi)容寫(xiě)入response:
    response.end('<h1>Hello world!</h1>');
});

// 讓服務(wù)器監(jiān)聽(tīng)8080端口:
server.listen(8080);

console.log('Server is running at http://127.0.0.1:8080/');

7、crypto

crypto模塊的目的是為了提供通用的加密和哈希算法

7.1MD5

MD5是一種常用的哈希算法,用于給任意數(shù)據(jù)一個(gè)“簽名”。這個(gè)簽名通常用一個(gè)十六進(jìn)制的字符串表示:

const crypto = require('crypto');

const hash = crypto.createHash('md5');

// 可任意多次調(diào)用update():
hash.update('Hello, world!');
hash.update('Hello, nodejs!');

console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544

7.2、其他加密算法

Hmac算法也是一種哈希算法,它可以利用MD5或SHA1等哈希算法。不同的是,Hmac還需要一個(gè)密鑰,Hmac理解為用隨機(jī)數(shù)“增強(qiáng)”的哈希算法

AES是一種常用的對(duì)稱加密算法,加解密都用同一個(gè)密鑰

DH算法是一種密鑰交換協(xié)議,它可以讓雙方在不泄漏密鑰的情況下協(xié)商出一個(gè)密鑰來(lái)

RSA算法是一種非對(duì)稱加密算法,即由一個(gè)私鑰和一個(gè)公鑰構(gòu)成的密鑰對(duì),通過(guò)私鑰加密,公鑰解密,或者通過(guò)公鑰加密,私鑰解密。其中,公鑰可以公開(kāi),私鑰必須保密。

8、路由(url)

我們要為路由提供請(qǐng)求的 URL 和其他需要的 GET 及 POST 參數(shù),隨后路由需要根據(jù)這些數(shù)據(jù)來(lái)執(zhí)行相應(yīng)的代碼

https://www.runoob.com/nodejs/nodejs-router.html

9、GET/POST請(qǐng)求

https://www.runoob.com/nodejs/node-js-get-post.html

9、nodejs連接 MySQL

9.1、安裝mysql

cnpm install mysql

連接數(shù)據(jù)庫(kù),并執(zhí)行查詢語(yǔ)句

var mysql  = require('mysql');  

var connection = mysql.createConnection({     
  host     : 'localhost',       
  user     : 'root',              
  password : '123456',       
  port: '3306',                   
  database: 'test' 
}); 

connection.connect();

var  sql = 'SELECT * FROM websites';
//查
connection.query(sql,function (err, result) {
        if(err){
          console.log('[SELECT ERROR] - ',err.message);
          return;
        }

       console.log('--------------------------SELECT----------------------------');
       console.log(result);
       console.log('------------------------------------------------------------\n\n');  
});

connection.end();

9.2、connection.query查詢方式

第一個(gè)參數(shù)是一個(gè)SQL語(yǔ)句,可以是任意的數(shù)據(jù)庫(kù)語(yǔ)句,而第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),查詢結(jié)果通過(guò)回調(diào)參數(shù)的方式返回。

connection.query('select * from book where author = "xyf" and country = "china"',function(err, result) {
    console.log(result);
    }
);

第二種 占位符注入查詢

第二種查詢方式是采用了占位符的形式connection.query(sqlString, values, callback) ,這樣就不需要進(jìn)行惡心的字符串的拼接了。

connection.query('select * from book where author = ? and country = ?',
['xyf', 'china'],function(err, result) {
    console.log(result);

    }
);

第三種 使用對(duì)象查詢方式

第三種查詢方式我們將查詢語(yǔ)句和查詢值組合成一個(gè)對(duì)象來(lái)進(jìn)行查詢。它的形式是這樣的:connection.query(object, callback)

connection.query(
    {
    sql:'select * from book where author = ? and country = ?',

    values: ['xyf', 'china'], //作為對(duì)象的屬性

    timeout: 40000,},function(err, result) { console.log(result);}
);

10、REST

REST就是一種設(shè)計(jì)API的模式,最常用的數(shù)據(jù)格式是JSON

1、REST即表述性狀態(tài)傳遞(英文:Representational State Transfer,簡(jiǎn)稱REST)是Roy Fielding博士在2000年他的博士論文中提出來(lái)的一種軟件架構(gòu)風(fēng)格

2、HTTP 方法

以下為 REST 基本架構(gòu)的四個(gè)方法:

  • GET - 用于獲取數(shù)據(jù)。
  • PUT - 用于更新或添加數(shù)據(jù)。
  • DELETE - 用于刪除數(shù)據(jù)。
  • POST - 用于添加數(shù)據(jù)。

拓展內(nèi)容

1、Express(提供了最簡(jiǎn)單而強(qiáng)大的方式來(lái)創(chuàng)建 Web 服務(wù)器。它的極簡(jiǎn)主義方法、沒(méi)有偏見(jiàn)、專注于服務(wù)器的核心功能,是其成功的關(guān)鍵)

2、Koa2(Koa 是一個(gè)新的 web 框架,由 Express 幕后的原班人馬打造, 致力于成為 web 應(yīng)用和 API 開(kāi)發(fā)領(lǐng)域中的一個(gè)更小、更富有表現(xiàn)力、更健壯的基石)

3、Egg.js(使用 Node.js 和 Koa 構(gòu)建更好的企業(yè)級(jí)框架和應(yīng)用程序的框架)

4、NestJs(基于 TypeScript 的漸進(jìn)式 Node.js 框架,用于構(gòu)建企業(yè)級(jí)的高效、可靠和可擴(kuò)展的服務(wù)器端應(yīng)用程序)

5、Socket.io (構(gòu)建網(wǎng)絡(luò)應(yīng)用的實(shí)時(shí)通信引擎)

6、js模板引擎(EJS、Nunjucks)

7、MySql (關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng))/ MongoDB(非關(guān)系型數(shù)據(jù)庫(kù))

7.1、數(shù)據(jù)庫(kù)CRUD

# 插入數(shù)據(jù)
INSERT INTO table_name ( field1, field2,...fieldN )
                       VALUES
                       ( value1, value2,...valueN )
# 查詢數(shù)據(jù)
SELECT column_name,column_name
FROM table_name
[WHERE Clause]
[LIMIT N][ OFFSET M]

# 修改數(shù)據(jù)
UPDATE table_name SET field1=new-value1, field2=new-value2
[WHERE Clause]

# 刪除數(shù)據(jù)
DELETE FROM table_name [WHERE Clause]

# 多表查詢
# tcount_tbl
mysql> SELECT * FROM tcount_tbl;
+---------------+--------------+
| runoob_author | runoob_count |
+---------------+--------------+
| 菜鳥(niǎo)教程  | 10           |
| RUNOOB.COM    | 20           |
| Google        | 22           |
+---------------+--------------+
# runoob_tbl
mysql> SELECT * from runoob_tbl;
+-----------+---------------+---------------+-----------------+
| runoob_id | runoob_title  | runoob_author | submission_date |
+-----------+---------------+---------------+-----------------+
| 1         | 學(xué)習(xí) PHP    | 菜鳥(niǎo)教程  | 2017-04-12      |
| 2         | 學(xué)習(xí) MySQL  | 菜鳥(niǎo)教程  | 2017-04-12      |
| 3         | 學(xué)習(xí) Java   | RUNOOB.COM    | 2015-05-01      |
| 4         | 學(xué)習(xí) Python | RUNOOB.COM    | 2016-03-06      |
| 5         | 學(xué)習(xí) C      | FK            | 2017-04-05      |
+-----------+---------------+---------------+-----------------+

INNER JOIN(內(nèi)連接,或等值連接):獲取兩個(gè)表中字段匹配關(guān)系的記錄。 INNER JOIN  中 INNER可以省略
mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count FROM runoob_tbl a INNER JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1           | 菜鳥(niǎo)教程    | 10             |
| 2           | 菜鳥(niǎo)教程    | 10             |
| 3           | RUNOOB.COM      | 20             |
| 4           | RUNOOB.COM      | 20             |
+-------------+-----------------+----------------+

LEFT JOIN(左連接):獲取左表所有記錄,即使右表沒(méi)有對(duì)應(yīng)匹配的記錄。
mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count FROM runoob_tbl a LEFT JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1           | 菜鳥(niǎo)教程    | 10             |
| 2           | 菜鳥(niǎo)教程    | 10             |
| 3           | RUNOOB.COM      | 20             |
| 4           | RUNOOB.COM      | 20             |
| 5           | FK              | NULL           |
+-------------+-----------------+----------------+
RIGHT JOIN(右連接): 與 LEFT JOIN 相反,用于獲取右表所有記錄,即使左表沒(méi)有對(duì)應(yīng)匹配的記錄

mysql> SELECT a.runoob_id, a.runoob_author, b.runoob_count FROM runoob_tbl a RIGHT JOIN tcount_tbl b ON a.runoob_author = b.runoob_author;
+-------------+-----------------+----------------+
| a.runoob_id | a.runoob_author | b.runoob_count |
+-------------+-----------------+----------------+
| 1           | 菜鳥(niǎo)教程    | 10             |
| 2           | 菜鳥(niǎo)教程    | 10             |
| 3           | RUNOOB.COM      | 20             |
| 4           | RUNOOB.COM      | 20             |
| NULL        | NULL            | 22             |
+-------------+-----------------+----------------+

# 子查詢(相關(guān)子查詢和非相關(guān)子查詢)
嵌套在其他查詢中的查詢即子查詢,子查詢也叫內(nèi)部查詢,子查詢總是從內(nèi)向外處理。
SELECT * FROM tab1 WHERE size IN (
    SELECT size FROM tab2
)
相關(guān)子查詢:指查詢結(jié)果依賴于外部查詢的子查詢,外部查詢每執(zhí)行一次,內(nèi)部子查詢也會(huì)執(zhí)行一次
非相關(guān)子查詢:指獨(dú)立于外部查詢的子查詢,內(nèi)部子查詢僅執(zhí)行一次,執(zhí)行完畢后將查詢結(jié)果作為外部查詢的條件使用
不依賴與外部的查詢
非相關(guān)子查詢一般可以分為:
    返回單值的子查詢
    返回一個(gè)列表的子查詢

# MySQL中數(shù)據(jù)的基本查詢方式

1.查詢所有列

  select * from 表名稱;

2.查詢指定列

  select 字段名,字段名,字段名 from 表名稱;

3.查詢時(shí)添加常量列(臨時(shí)備注)

  select 字段名,字段名,字段名,字段名 as 備注 from 表名稱;

4.查詢時(shí)合并列(合并列只能合并數(shù)值類(lèi)型的字段)

  select 字段名,(字段名+字段名) from 表名稱;

5.查詢時(shí)去除重復(fù)記錄

  select distinct 字段名 from 表名稱;

6.條件查詢(where)

 ?。?)邏輯條件:and(并)  or(或)

  select * from 表名稱 where 字段名=值 and 字段名=值;

  select * from 表名稱 where 字段名=值 or 字段名=值;

 ?。?)比較條件:>  <  >=  <=  =  <>(不等于)  between and(等價(jià)于>=且<=)

 ?。?)判空條件(null空字符串):is null  /  is not null  /  =  '  '  /<>  '  '

  null:表示沒(méi)有值   /   空字符串:有值,但是值是空字符串

  判斷null

  select * from 表名稱 where 字段名 is null;

  判斷空字符串

  select * from 表名稱 where 字段名='  ';

  判斷null和空字符串

  select * from 表名稱 where 字段名 is null or 字段名='  ';

  查詢不包括null和空字符串的字段

  select * from 表名稱 where 字段名 is not null and 字段名<> '  ';

  (4)模糊條件:like

  通常用一下替換標(biāo)記:

  %:表示任意個(gè)字符

  _:表示一個(gè)字符

  select * from 表名稱 where 字段名 like '部分值%';

7.聚合查詢(使用聚合函數(shù)的查詢)

  常用的聚合函數(shù):sum()求和   avg()求平均值   max()求最大值   min()求最小值   count()計(jì)數(shù)

  用法:select 聚合函數(shù)(字段名) from 表名稱;

  注意:count()函數(shù)統(tǒng)計(jì)的數(shù)量不包含null的數(shù)據(jù),使用count統(tǒng)計(jì)表的記錄數(shù),要使用不包含null值的字段。

8. 分頁(yè)查詢(limit起始行,查詢幾行)

  起始行從0開(kāi)始

  分頁(yè):當(dāng)前頁(yè)  每頁(yè)顯示多少條

  分頁(yè)查詢當(dāng)前頁(yè)的數(shù)據(jù)的sql:select * from 表名稱 limit(當(dāng)前頁(yè)-1) 每頁(yè)顯示多少條,每頁(yè)顯示多少條;

例如:查詢第1,2條記錄(第一頁(yè)的數(shù)據(jù))

  select * from 表名稱 limit 0,2;(當(dāng)前頁(yè)-1再乘以2,顯示幾條數(shù)據(jù))

  查詢第3,4條記錄(第二頁(yè)的數(shù)據(jù))

  select * from 表名稱 limit 2,2;

  查詢第5,6條記錄(第三頁(yè)的數(shù)據(jù))

  select * from 表名稱 limit 4,2;

  查詢第7,8條記錄

  select * from 表名稱 limit 6,2; 

9. 查詢排序(order by)

  語(yǔ)法:order by 字段 asc/desc

  asc:順序,正序。數(shù)值:遞增,字母:自然順序(a-z)

  desc:倒序,反序。數(shù)值:遞減,字母:自然反序(z-a)

  默認(rèn)情況下,按照插入記錄順序排序

  select * from 表名稱 order by 字段名 asc/desc;

  注意:多個(gè)排序條件

  select * from 表名稱 order by 字段名 asc,字段名 desc;

10. 分組查詢(group by)

  select 字段名(同一個(gè)) from 表名稱 group by 字段名(同一個(gè));

11. 分組查詢后篩選

  注意:分組之前條件使用where關(guān)鍵字,分組之后條件使用having關(guān)鍵字,如分組后找出大于或者小于n的字段

  select 字段名,count(*) from 表名稱 group by 字段名 having count(*) 比較條件 n;

8、Mocha(一個(gè)功能豐富的javascript測(cè)試框架,運(yùn)行在node.js和瀏覽器中,使異步測(cè)試變得簡(jiǎn)單有趣)

9、Sequelize(Node的ORM框架Sequelize來(lái)操作數(shù)據(jù)庫(kù))

10、Nunjucks(模板引擎就是基于模板配合數(shù)據(jù)構(gòu)造出字符串輸出的一個(gè)組件)

11、EJS(高效的嵌入式 JavaScript 模板引擎)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容