Node.js安裝包及源碼下載地址爲:https://nodejs.org/en/download/javascript
Node.js 歷史版本下載地址:https://nodejs.org/dist/php
注意:Linux上安裝Node.js須要安裝Python 2.6 或 2.7 ,不建議安裝Python 3.0以上版本。html
32 位安裝包下載地址 : https://nodejs.org/dist/v4.4.3/node-v4.4.3-x86.msijava
64 位安裝包下載地址 : https://nodejs.org/dist/v4.4.3/node-v4.4.3-x64.msinode
本文實例以 v0.10.26 版本爲例,其餘版本相似, 安裝步驟:python
步驟 1 : 雙擊下載後的安裝包 v0.10.26,以下所示:mysql
步驟 2 : 點擊以上的Run(運行),將出現以下界面:linux
步驟 3 : 勾選接受協議選項,點擊 next(下一步) 按鈕 :git
步驟 4 : Node.js默認安裝目錄爲 "C:\Program Files\nodejs\" , 你能夠修改目錄,並點擊 next(下一步):github
步驟 5 : 點擊樹形圖標來選擇你須要的安裝模式 , 而後點擊下一步 next(下一步)
步驟 6 :點擊 Install(安裝) 開始安裝Node.js。你也能夠點擊 Back(返回)來修改先前的配置。 而後並點擊 next(下一步):
安裝過程:
點擊 Finish(完成)按鈕退出安裝嚮導。
檢測PATH環境變量是否配置了Node.js,點擊開始=》運行=》輸入"cmd" => 輸入命令"path",輸出以下結果:
PATH=C:\oraclexe\app\oracle\product\10.2.0\server\bin;C:\Windows\system32;
C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;
c:\python32\python;C:\MinGW\bin;C:\Program Files\GTK2-Runtime\lib;
C:\Program Files\MySQL\MySQL Server 5.5\bin;C:\Program Files\nodejs\;
C:\Users\rg\AppData\Roaming\npm
咱們能夠看到環境變量中已經包含了C:\Program Files\nodejs\
檢查Node.js版本
咱們使用 require 指令來載入 http 模塊,並將實例化的 HTTP 賦值給變量 http,實例以下:
var http = require("http");
接下來咱們使用 http.createServer() 方法建立服務器,並使用 listen 方法綁定 8888 端口。 函數經過 request, response 參數來接收和響應數據。
實例以下,在你項目的根目錄下建立一個叫 server.js 的文件,並寫入如下代碼:
var http = require('http');
http.createServer(function (request, response) {
// 發送 HTTP 頭部
// HTTP 狀態值: 200 : OK
// 內容類型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 發送響應數據 "Hello World"
response.end('Hello World\n');
}).listen(8888);
// 終端打印以下信息
console.log('Server running at http://127.0.0.1:8888/');
以上代碼咱們完成了一個能夠工做的 HTTP 服務器。
使用 node 命令執行以上的代碼:
node server.js
Server running at http://127.0.0.1:8888/
接下來,打開瀏覽器訪問 http://127.0.0.1:8888/,你會看到一個寫着 "Hello World"的網頁。
分析Node.js 的 HTTP 服務器:
NPM是隨同NodeJS一塊兒安裝的包管理工具,能解決NodeJS代碼部署上的不少問題,常見的使用場景有如下幾種:
因爲新版的nodejs已經集成了npm,因此以前npm也一併安裝好了。一樣能夠經過輸入 "npm -v" 來測試是否成功安裝。命令以下,出現版本提示表示安裝成功:
$ npm -v
2.3.0
若是你安裝的是舊版本的 npm,能夠很容易得經過 npm 命令來升級,命令以下:
$ sudo npm install npm -g
/usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js
npm@2.14.2 /usr/local/lib/node_modules/npm
若是是 Window 系統使用如下命令便可:
npm install npm -g
使用淘寶鏡像的命令:
cnpm install npm -g
npm 安裝 Node.js 模塊語法格式以下:
$ npm install <Module Name>
如下實例,咱們使用 npm 命令安裝經常使用的 Node.js web框架模塊 express:
$ npm install express
安裝好以後,express 包就放在了工程目錄下的 node_modules 目錄中,所以在代碼中只須要經過 require('express') 的方式就好,無需指定第三方包路徑。
var express = require('express');
npm 的包安裝分爲本地安裝(local)、全局安裝(global)兩種,從敲的命令行來看,差異只是有沒有-g而已,好比
npm install express # 本地安裝
npm install express -g # 全局安裝
若是出現如下錯誤:
npm err! Error: connect ECONNREFUSED 127.0.0.1:8087
解決辦法爲:
$ npm config set proxy null
若是你但願具有二者功能,則須要在兩個地方安裝它或使用 npm link。
接下來咱們使用全局方式安裝 express
$ npm install express -g
安裝過程輸出以下內容,第一行輸出了模塊的版本號及安裝位置。
express@4.13.3 node_modules/express
├── escape-html@1.0.2
├── range-parser@1.0.2
├── merge-descriptors@1.0.0
├── array-flatten@1.1.1
├── cookie@0.1.3
├── utils-merge@1.0.0
├── parseurl@1.3.0
├── cookie-signature@1.0.6
├── methods@1.1.1
├── fresh@0.3.0
├── vary@1.0.1
├── path-to-regexp@0.1.7
├── content-type@1.0.1
├── etag@1.7.0
├── serve-static@1.10.0
├── content-disposition@0.5.0
├── depd@1.0.1
├── qs@4.0.0
├── finalhandler@0.4.0 (unpipe@1.0.0)
├── on-finished@2.3.0 (ee-first@1.1.1)
├── proxy-addr@1.0.8 (forwarded@0.1.0, ipaddr.js@1.0.1)
├── debug@2.2.0 (ms@0.7.1)
├── type-is@1.6.8 (media-typer@0.3.0, mime-types@2.1.6)
├── accepts@1.2.12 (negotiator@0.5.3, mime-types@2.1.6)
└── send@0.13.0 (destroy@1.0.3, statuses@1.2.1, ms@0.7.1, mime@1.3.4, http-errors@1.3.1)
你可使用如下命令來查看全部全局安裝的模塊:
$ npm list -g
├─┬ cnpm@4.3.2
│ ├── auto-correct@1.0.0
│ ├── bagpipe@0.3.5
│ ├── colors@1.1.2
│ ├─┬ commander@2.9.0
│ │ └── graceful-readlink@1.0.1
│ ├─┬ cross-spawn@0.2.9
│ │ └── lru-cache@2.7.3
……
若是要查看某個模塊的版本號,可使用命令以下:
$ npm list grunt
projectName@projectVersion /path/to/project/folder
└── grunt@0.4.1
package.json 位於模塊的目錄下,用於定義包的屬性。接下來讓咱們來看下 express 包的 package.json 文件,位於 node_modules/express/package.json 內容:
{
"name": "express",
"description": "Fast, unopinionated, minimalist web framework",
"version": "4.13.3",
"author": {
"name": "TJ Holowaychuk",
"email": "tj@vision-media.ca"
},
"contributors": [
{
"name": "Aaron Heckmann",
"email": "aaron.heckmann+github@gmail.com"
},
{
"name": "Ciaran Jessup",
"email": "ciaranj@gmail.com"
},
{
"name": "Douglas Christopher Wilson",
"email": "doug@somethingdoug.com"
},
{
"name": "Guillermo Rauch",
"email": "rauchg@gmail.com"
},
{
"name": "Jonathan Ong",
"email": "me@jongleberry.com"
},
{
"name": "Roman Shtylman",
"email": "shtylman+expressjs@gmail.com"
},
{
"name": "Young Jae Sim",
"email": "hanul@hanul.me"
}
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/strongloop/express.git"
},
"homepage": "http://expressjs.com/",
"keywords": [
"express",
"framework",
"sinatra",
"web",
"rest",
"restful",
"router",
"app",
"api"
],
"dependencies": {
"accepts": "~1.2.12",
"array-flatten": "1.1.1",
"content-disposition": "0.5.0",
"content-type": "~1.0.1",
"cookie": "0.1.3",
"cookie-signature": "1.0.6",
"debug": "~2.2.0",
"depd": "~1.0.1",
"escape-html": "1.0.2",
"etag": "~1.7.0",
"finalhandler": "0.4.0",
"fresh": "0.3.0",
"merge-descriptors": "1.0.0",
"methods": "~1.1.1",
"on-finished": "~2.3.0",
"parseurl": "~1.3.0",
"path-to-regexp": "0.1.7",
"proxy-addr": "~1.0.8",
"qs": "4.0.0",
"range-parser": "~1.0.2",
"send": "0.13.0",
"serve-static": "~1.10.0",
"type-is": "~1.6.6",
"utils-merge": "1.0.0",
"vary": "~1.0.1"
},
"devDependencies": {
"after": "0.8.1",
"ejs": "2.3.3",
"istanbul": "0.3.17",
"marked": "0.3.5",
"mocha": "2.2.5",
"should": "7.0.2",
"supertest": "1.0.1",
"body-parser": "~1.13.3",
"connect-redis": "~2.4.1",
"cookie-parser": "~1.3.5",
"cookie-session": "~1.2.0",
"express-session": "~1.11.3",
"jade": "~1.11.0",
"method-override": "~2.3.5",
"morgan": "~1.6.1",
"multiparty": "~4.1.2",
"vhost": "~3.0.1"
},
"engines": {
"node": ">= 0.10.0"
},
"files": [
"LICENSE",
"History.md",
"Readme.md",
"index.js",
"lib/"
],
"scripts": {
"test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/",
"test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/",
"test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/"
},
"gitHead": "ef7ad681b245fba023843ce94f6bcb8e275bbb8e",
"bugs": {
"url": "https://github.com/strongloop/express/issues"
},
"_id": "express@4.13.3",
"_shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3",
"_from": "express@*",
"_npmVersion": "1.4.28",
"_npmUser": {
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
"maintainers": [
{
"name": "tjholowaychuk",
"email": "tj@vision-media.ca"
},
{
"name": "jongleberry",
"email": "jonathanrichardong@gmail.com"
},
{
"name": "dougwilson",
"email": "doug@somethingdoug.com"
},
{
"name": "rfeng",
"email": "enjoyjava@gmail.com"
},
{
"name": "aredridel",
"email": "aredridel@dinhe.net"
},
{
"name": "strongloop",
"email": "callback@strongloop.com"
},
{
"name": "defunctzombie",
"email": "shtylman@gmail.com"
}
],
"dist": {
"shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3",
"tarball": "http://registry.npmjs.org/express/-/express-4.13.3.tgz"
},
"directories": {},
"_resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz",
"readme": "ERROR: No README data found!"
}
咱們可使用如下命令來卸載 Node.js 模塊。
$ npm uninstall express
卸載後,你能夠到 /node_modules/ 目錄下查看包是否還存在,或者使用如下命令查看:
$ npm ls
咱們可使用如下命令更新模塊:
$ npm update express
使用如下來搜索模塊:
$ npm search express
建立模塊,package.json 文件是必不可少的。咱們可使用 NPM 生成 package.json 文件,生成的文件包含了基本的結果。
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (node_modules) runoob # 模塊名
version: (1.0.0)
description: Node.js 測試模塊(www.runoob.com) # 描述
entry point: (index.js)
test command: make test
git repository: https://github.com/runoob/runoob.git # Github 地址
keywords:
author:
license: (ISC)
About to write to ……/node_modules/package.json: # 生成地址
{
"name": "runoob",
"version": "1.0.0",
"description": "Node.js 測試模塊(www.runoob.com)",
……
}
Is this ok? (yes) yes
以上的信息,你須要根據你本身的狀況輸入。在最後輸入 "yes" 後會生成 package.json 文件。
接下來咱們可使用如下命令在 npm 資源庫中註冊用戶(使用郵箱註冊):
$ npm adduser
Username: mcmohd
Password:
Email: (this IS public) mcmohd@gmail.com
接下來咱們就用如下命令來發布模塊:
$ npm publish
若是你以上的步驟都操做正確,你就能夠跟其餘模塊同樣使用 npm 來安裝。
使用NPM下載和發佈代碼時都會接觸到版本號。NPM使用語義版本號來管理代碼,這裏簡單介紹一下。
語義版本號分爲X.Y.Z三位,分別表明主版本號、次版本號和補丁版本號。當代碼變動時,版本號按如下原則更新。
版本號有了這個保證後,在申明第三方包依賴時,除了可依賴於一個固定版本號外,還可依賴於某個範圍的版本號。例如"argv": "0.0.x"表示依賴於0.0.x系列的最新版argv。
NPM支持的全部版本號範圍指定方式能夠查看官方文檔。
除了本章介紹的部分外,NPM還提供了不少功能,package.json裏也有不少其它有用的字段。
除了能夠在npmjs.org/doc/查看官方文檔外,這裏再介紹一些NPM經常使用命令。
NPM提供了不少命令,例如install和publish,使用npm help可查看全部命令。
install
和publish
,使用npm help
可查看全部命令。npm help <command>
可查看某條命令的詳細幫助,例如npm help install
。package.json
所在目錄下使用npm install . -g
可先在本地安裝當前命令行程序,可用於發佈前的本地測試。npm update <package>
能夠把當前目錄下node_modules
子目錄裏邊的對應模塊更新至最新版本。npm update <package> -g
能夠把全局安裝的對應命令行程序更新至最新版。npm cache clear
能夠清空NPM本地緩存,用於對付使用相同版本號發佈新版本代碼的人。npm unpublish <package>@<version>
能夠撤銷發佈本身發佈過的某個版本代碼。你們都知道國內直接使用 npm 的官方鏡像是很是慢的,這裏推薦使用淘寶 NPM 鏡像。
淘寶 NPM 鏡像是一個完整 npmjs.org 鏡像,你能夠用此代替官方版本(只讀),同步頻率目前爲 10分鐘 一次以保證儘可能與官方服務同步。
你可使用淘寶定製的 cnpm (gzip 壓縮支持) 命令行工具代替默認的 npm:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
這樣就可使用 cnpm 命令來安裝模塊了:
$ cnpm install [name]
Node.js REPL(Read Eval Print Loop:交互式解釋器) 表示一個電腦的環境,相似 Window 系統的終端或 Unix/Linux shell,咱們能夠在終端中輸入命令,並接收系統的響應。
Node 自帶了交互式解釋器,能夠執行如下任務:
Node 的交互式解釋器能夠很好的調試 Javascript 代碼。
開始學習 REPL
咱們能夠輸入如下命令來啓動 Node 的終端:
$ node
>
這時咱們就能夠在 > 後輸入簡單的表達式,並按下回車鍵來計算結果。
接下來讓咱們在 Node.js REPL 的命令行窗口中執行簡單的數學運算:
$ node
> 1 +4
5
> 5 / 2
2.5
> 3 * 6
18
> 4 - 1
3
> 1 + ( 2 * 3 ) - 4
3
>
你能夠將數據存儲在變量中,並在你須要的時候使用它。
變量聲明須要使用 var 關鍵字,若是沒有使用 var 關鍵字變量會直接打印出來。
使用 var 關鍵字的變量可使用 console.log() 來輸出變量。
$ node
> x = 10
10
> var y = 10
undefined
> x + y
20
> console.log("Hello World")
Hello World
undefined
> console.log("www.runoob.com")
www.runoob.com
undefined
Node REPL 支持輸入多行表達式,這就有點相似 JavaScript。接下來讓咱們來執行一個 do-while 循環:
$ node
> var x = 0
undefined
> do {
... x++;
... console.log("x: " + x);
... } while ( x < 5 );
x: 1
x: 2
x: 3
x: 4
x: 5
undefined
>
... 三個點的符號是系統自動生成的,你回車換行後便可。Node 會自動檢測是否爲連續的表達式。
你可使用下劃線(_)獲取上一個表達式的運算結果:
$ node
> var x = 10
undefined
> var y = 20
undefined
> x + y
30
> var sum = _
undefined
> console.log(sum)
30
undefined
>
前面咱們已經提到按下兩次 ctrl + c 鍵就能退出 REPL:
$ node
>
(^C again to quit)
>
Node.js 異步編程的直接體現就是回調。
異步編程依託於回調來實現,但不能說使用了回調後程序就異步化了。
回調函數在完成任務後就會被調用,Node 使用了大量的回調函數,Node 全部 API 都支持回調函數。
例如,咱們能夠一邊讀取文件,一邊執行其餘命令,在文件讀取完成後,咱們將文件內容做爲回調函數的參數返回。這樣在執行代碼時就沒有阻塞或等待文件 I/O 操做。這就大大提升了 Node.js 的性能,能夠處理大量的併發請求。
建立一個文件 input.txt ,內容以下:
菜鳥教程官網地址:www.runoob.com
建立 main.js 文件, 代碼以下:
var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序執行結束!");
以上代碼執行結果以下:
$ node main.js
菜鳥教程官網地址:www.runoob.com
程序執行結束!
建立一個文件 input.txt ,內容以下:
菜鳥教程官網地址:www.runoob.com
建立 main.js 文件, 代碼以下:
var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
if (err) return console.error(err);
console.log(data.toString());
});
console.log("程序執行結束!");
以上代碼執行結果以下:
$ node main.js
程序執行結束!
菜鳥教程官網地址:www.runoob.com
以上兩個實例咱們瞭解了阻塞與非阻塞調用的不一樣。第一個實例在文件讀取完後才執行完程序。 第二個實例咱們不須要等待文件讀取完,這樣就能夠在讀取文件時同時執行接下來的代碼,大大提升了程序的性能。
所以,阻塞是按順序執行的,而非阻塞是不須要按順序的,因此若是須要處理回調函數的參數,咱們就須要寫在回調函數內。
Node.js 是單進程單線程應用程序,可是經過事件和回調支持併發,因此性能很是高。
Node.js 的每個 API 都是異步的,並做爲一個獨立線程運行,使用異步函數調用,並處理併發。
Node.js 基本上全部的事件機制都是用設計模式中觀察者模式實現。
Node.js 單線程相似進入一個while(true)的事件循環,直到沒有事件觀察者退出,每一個異步事件都生成一個事件觀察者,若是有事件發生就調用該回調函數.
Node.js 使用事件驅動模型,當web server接收到請求,就把它關閉而後進行處理,而後去服務下一個web請求。
當這個請求完成,它被放回處理隊列,當到達隊列開頭,這個結果被返回給用戶。
這個模型很是高效可擴展性很是強,由於webserver一直接受請求而不等待任何讀寫操做。(這也被稱之爲非阻塞式IO或者事件驅動IO)
在事件驅動模型中,會生成一個主循環來監聽事件,當檢測到事件時觸發回調函數。
整個事件驅動的流程就是這麼實現的,很是簡潔。有點相似於觀察者模式,事件至關於一個主題(Subject),而全部註冊到這個事件上的處理函數至關於觀察者(Observer)。
Node.js 有多個內置的事件,咱們能夠經過引入 events 模塊,並經過實例化 EventEmitter 類來綁定和監聽事件,以下實例:
// 引入 events 模塊
var events = require('events');
// 建立 eventEmitter 對象
var eventEmitter = new events.EventEmitter();
如下程序綁定事件處理程序:
// 綁定事件及事件的處理程序
eventEmitter.on('eventName', eventHandler);
咱們能夠經過程序觸發事件:
// 觸發事件
eventEmitter.emit('eventName');
建立 main.js 文件,代碼以下所示:
// 引入 events 模塊
var events = require('events');
// 建立 eventEmitter 對象
var eventEmitter = new events.EventEmitter();
// 建立事件處理程序
var connectHandler = function connected() {
console.log('鏈接成功。');
// 觸發 data_received 事件
eventEmitter.emit('data_received');
}
// 綁定 connection 事件處理程序
eventEmitter.on('connection', connectHandler);
// 使用匿名函數綁定 data_received 事件
eventEmitter.on('data_received', function(){
console.log('數據接收成功。');
});
// 觸發 connection 事件
eventEmitter.emit('connection');
console.log("程序執行完畢。");
接下來讓咱們執行以上代碼:
$ node main.js
鏈接成功。
數據接收成功。
程序執行完畢。
Node.js 全部的異步 I/O 操做在完成時都會發送一個事件到事件隊列。
Node.js裏面的許多對象都會分發事件:一個net.Server對象會在每次有新鏈接時分發一個事件, 一個fs.readStream對象會在文件被打開的時候發出一個事件。 全部這些產生事件的對象都是 events.EventEmitter 的實例。
events 模塊只提供了一個對象: events.EventEmitter。EventEmitter 的核心就是事件觸發與事件監聽器功能的封裝。
你能夠經過require("events");來訪問該模塊。
// 引入 events 模塊
var events = require('events');
// 建立 eventEmitter 對象
var eventEmitter = new events.EventEmitter();
EventEmitter 對象若是在實例化時發生錯誤,會觸發 error 事件。當添加新的監聽器時,newListener 事件會觸發,當監聽器被移除時,removeListener 事件被觸發。
下面咱們用一個簡單的例子說明 EventEmitter 的用法:
//event.js 文件
var EventEmitter = require('events').EventEmitter;
var event = new EventEmitter();
event.on('some_event', function() {
console.log('some_event 事件觸發');
});
setTimeout(function() {
event.emit('some_event');
}, 1000);
執行結果以下:
運行這段代碼,1 秒後控制檯輸出了 'some_event 事件觸發'。其原理是 event 對象註冊了事件 some_event 的一個監聽器,而後咱們經過 setTimeout 在 1000 毫秒之後向 event 對象發送事件 some_event,此時會調用some_event 的監聽器。
$ node event.js
some_event 事件觸發
EventEmitter 的每一個事件由一個事件名和若干個參數組成,事件名是一個字符串,一般表達必定的語義。對於每一個事件,EventEmitter 支持 若干個事件監聽器。
當事件觸發時,註冊到這個事件的事件監聽器被依次調用,事件參數做爲回調函數參數傳遞。
讓咱們如下面的例子解釋這個過程:
//event.js 文件
var events = require('events');
var emitter = new events.EventEmitter();
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener1', arg1, arg2);
});
emitter.on('someEvent', function(arg1, arg2) {
console.log('listener2', arg1, arg2);
});
emitter.emit('someEvent', 'arg1 參數', 'arg2 參數');
執行以上代碼,運行的結果以下:
$ node event.js
listener1 arg1 參數 arg2 參數
listener2 arg1 參數 arg2 參數
以上例子中,emitter 爲事件 someEvent 註冊了兩個事件監聽器,而後觸發了 someEvent 事件。
運行結果中能夠看到兩個事件監聽器回調函數被前後調用。 這就是EventEmitter最簡單的用法。
EventEmitter 提供了多個屬性,如 on 和 emit。on 函數用於綁定事件函數,emit 屬性用於觸發一個事件。接下來咱們來具體看下 EventEmitter 的屬性介紹。
序號 |
方法 & 描述 |
1 |
addListener(event, listener) |
2 |
on(event, listener) server.on('connection', function (stream) { console.log('someone connected!'); }); |
3 |
once(event, listener) server.once('connection', function (stream) { console.log('Ah, we have our first user!'); }); |
4 |
removeListener(event, listener) 移除指定事件的某個監聽器,監聽器必須是該事件已經註冊過的監聽器。 它接受兩個參數,第一個是事件名稱,第二個是回調函數名稱。 var callback = function(stream) { console.log('someone connected!'); }; server.on('connection', callback); // ... server.removeListener('connection', callback); |
5 |
removeAllListeners([event]) |
6 |
setMaxListeners(n) |
7 |
listeners(event) |
8 |
emit(event, [arg1], [arg2], [...]) |
序號 |
方法 & 描述 |
1 |
listenerCount(emitter, event) |
序號 |
事件 & 描述 |
1 |
newListener
該事件在添加新監聽器時被觸發。 |
2 |
removeListener
從指定監聽器數組中刪除一個監聽器。須要注意的是,此操做將會改變處於被刪監聽器以後的那些監聽器的索引。 |
如下實例經過 connection(鏈接)事件演示了 EventEmitter 類的應用。
建立 main.js 文件,代碼以下:
var events = require('events');
var eventEmitter = new events.EventEmitter();
// 監聽器 #1
var listener1 = function listener1() {
console.log('監聽器 listener1 執行。');
}
// 監聽器 #2
var listener2 = function listener2() {
console.log('監聽器 listener2 執行。');
}
// 綁定 connection 事件,處理函數爲 listener1
eventEmitter.addListener('connection', listener1);
// 綁定 connection 事件,處理函數爲 listener2
eventEmitter.on('connection', listener2);
var eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 個監聽器監聽鏈接事件。");
// 處理 connection 事件
eventEmitter.emit('connection');
// 移除監綁定的 listener1 函數
eventEmitter.removeListener('connection', listener1);
console.log("listener1 再也不受監聽。");
// 觸發鏈接事件
eventEmitter.emit('connection');
eventListeners = require('events').EventEmitter.listenerCount(eventEmitter,'connection');
console.log(eventListeners + " 個監聽器監聽鏈接事件。");
console.log("程序執行完畢。");
以上代碼,執行結果以下所示:
$ node main.js
2 個監聽器監聽鏈接事件。
監聽器 listener1 執行。
監聽器 listener2 執行。
listener1 再也不受監聽。
監聽器 listener2 執行。
1 個監聽器監聽鏈接事件。
程序執行完畢。
EventEmitter 定義了一個特殊的事件 error,它包含了錯誤的語義,咱們在遇到 異常的時候一般會觸發 error 事件。
當 error 被觸發時,EventEmitter 規定若是沒有響 應的監聽器,Node.js 會把它看成異常,退出程序並輸出錯誤信息。
咱們通常要爲會觸發 error 事件的對象設置監聽器,避免遇到錯誤後整個程序崩潰。例如:
var events = require('events');
var emitter = new events.EventEmitter();
emitter.emit('error');
運行時會顯示如下錯誤:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Uncaught, unspecified 'error' event.
at EventEmitter.emit (events.js:50:15)
at Object.<anonymous> (/home/byvoid/error.js:5:9)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
大多數時候咱們不會直接使用 EventEmitter,而是在對象中繼承它。包括 fs、net、 http 在內的,只要是支持事件響應的核心模塊都是 EventEmitter 的子類。
爲何要這樣作呢?緣由有兩點:
首先,具備某個實體功能的對象實現事件符合語義, 事件的監聽和發生應該是一個對象的方法。
其次 JavaScript 的對象機制是基於原型的,支持 部分多重繼承,繼承 EventEmitter 不會打亂對象原有的繼承關係。
JavaScript 語言自身只有字符串數據類型,沒有二進制數據類型。
但在處理像TCP流或文件流時,必須使用到二進制數據。所以在 Node.js中,定義了一個 Buffer 類,該類用來建立一個專門存放二進制數據的緩存區。
在 Node.js 中,Buffer 類是隨 Node 內核一塊兒發佈的核心庫。Buffer 庫爲 Node.js 帶來了一種存儲原始數據的方法,可讓 Node.js 處理二進制數據,每當須要在 Node.js 中處理I/O操做中移動的數據時,就有可能使用 Buffer 庫。原始數據存儲在 Buffer 類的實例中。一個 Buffer 相似於一個整數數組,但它對應於 V8 堆內存以外的一塊原始內存。
在v6.0以前建立Buffer對象直接使用new Buffer()構造函數來建立對象實例,可是Buffer對內存的權限操做相比很大,能夠直接捕獲一些敏感信息,因此在v6.0之後,官方文檔裏面建議使用 Buffer.from() 接口去建立Buffer對象。
Buffer 實例通常用於表示編碼字符的序列,好比 UTF-8 、 UCS2 、 Base64 、或十六進制編碼的數據。 經過使用顯式的字符編碼,就能夠在 Buffer 實例與普通的 JavaScript 字符串之間進行相互轉換。
const buf = Buffer.from('runoob', 'ascii');
// 輸出 72756e6f6f62
console.log(buf.toString('hex'));
// 輸出 cnVub29i
console.log(buf.toString('base64'));
Node.js 目前支持的字符編碼包括:
Buffer 提供瞭如下 API 來建立 Buffer 類:
// 建立一個長度爲 十、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);
// 建立一個長度爲 十、且用 0x1 填充的 Buffer。
const buf2 = Buffer.alloc(10, 1);
// 建立一個長度爲 十、且未初始化的 Buffer。
// 這個方法比調用 Buffer.alloc() 更快,
// 但返回的 Buffer 實例可能包含舊數據,
// 所以須要使用 fill() 或 write() 重寫。
const buf3 = Buffer.allocUnsafe(10);
// 建立一個包含 [0x1, 0x2, 0x3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);
// 建立一個包含 UTF-8 字節 [0x74, 0xc3, 0xa9, 0x73, 0x74] 的 Buffer。
const buf5 = Buffer.from('tést');
// 建立一個包含 Latin-1 字節 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf6 = Buffer.from('tést', 'latin1');
寫入 Node 緩衝區的語法以下所示:
buf.write(string[, offset[, length]][, encoding])
參數描述以下:
根據 encoding 的字符編碼寫入 string 到 buf 中的 offset 位置。 length 參數是寫入的字節數。 若是 buf 沒有足夠的空間保存整個字符串,則只會寫入 string 的一部分。 只部分解碼的字符不會被寫入。
返回實際寫入的大小。若是 buffer 空間不足, 則只會寫入部分字符串。
buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");
console.log("寫入字節數 : "+ len);
執行以上代碼,輸出結果爲:
$node main.js
寫入字節數 : 14
讀取 Node 緩衝區數據的語法以下所示:
buf.toString([encoding[, start[, end]]])
參數描述以下:
解碼緩衝區數據並使用指定的編碼返回字符串。
buf = Buffer.alloc(26);
for (var i = 0 ; i < 26 ; i++) {
buf[i] = i + 97;
}
console.log( buf.toString('ascii')); // 輸出: abcdefghijklmnopqrstuvwxyz
console.log( buf.toString('ascii',0,5)); // 輸出: abcde
console.log( buf.toString('utf8',0,5)); // 輸出: abcde
console.log( buf.toString(undefined,0,5)); // 使用 'utf8' 編碼, 並輸出: abcde
執行以上代碼,輸出結果爲:
$ node main.js
abcdefghijklmnopqrstuvwxyz
abcde
abcde
abcde
將 Node Buffer 轉換爲 JSON 對象的函數語法格式以下:
buf.toJSON()
當字符串化一個 Buffer 實例時,JSON.stringify() 會隱式地調用該 toJSON()。
返回 JSON 對象。
const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
const json = JSON.stringify(buf);
// 輸出: {"type":"Buffer","data":[1,2,3,4,5]}
console.log(json);
const copy = JSON.parse(json, (key, value) => {
return value && value.type === 'Buffer' ?
Buffer.from(value.data) :
value;
});
// 輸出: <Buffer 01 02 03 04 05>
console.log(copy);
執行以上代碼,輸出結果爲:
{"type":"Buffer","data":[1,2,3,4,5]}
<Buffer 01 02 03 04 05>
Node 緩衝區合併的語法以下所示:
Buffer.concat(list[, totalLength])
參數描述以下:
返回一個多個成員合併的新 Buffer 對象。
var buffer1 = Buffer.from(('菜鳥教程'));
var buffer2 = Buffer.from(('www.runoob.com'));
var buffer3 = Buffer.concat([buffer1,buffer2]);
console.log("buffer3 內容: " + buffer3.toString());
執行以上代碼,輸出結果爲:
buffer3 內容: 菜鳥教程 www.runoob.com
Node Buffer 比較的函數語法以下所示, 該方法在 Node.js v0.12.2 版本引入:
buf.compare(otherBuffer);
參數描述以下:
返回一個數字,表示 buf 在 otherBuffer 以前,以後或相同。
var buffer1 = Buffer.from('ABC');
var buffer2 = Buffer.from('ABCD');
var result = buffer1.compare(buffer2);
if(result < 0) {
console.log(buffer1 + " 在 " + buffer2 + "以前");
}else if(result == 0){
console.log(buffer1 + " 與 " + buffer2 + "相同");
}else {
console.log(buffer1 + " 在 " + buffer2 + "以後");
}
執行以上代碼,輸出結果爲:
ABC在ABCD以前
Node 緩衝區拷貝語法以下所示:
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
參數描述以下:
沒有返回值。
var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('RUNOOB');
//將 buf2 插入到 buf1 指定位置上
buf2.copy(buf1, 2);
console.log(buf1.toString());
執行以上代碼,輸出結果爲:
abRUNOOBijkl
Node 緩衝區裁剪語法以下所示:
buf.slice([start[, end]])
參數描述以下:
返回一個新的緩衝區,它和舊緩衝區指向同一塊內存,可是從索引 start 到 end 的位置剪切。
var buffer1 = Buffer.from('runoob');
// 剪切緩衝區
var buffer2 = buffer1.slice(0,2);
console.log("buffer2 content: " + buffer2.toString());
執行以上代碼,輸出結果爲:
buffer2 content: ru
Node 緩衝區長度計算語法以下所示:
buf.length;
返回 Buffer 對象所佔據的內存長度。
var buffer = Buffer.from('www.runoob.com');
// 緩衝區長度
console.log("buffer length: " + buffer.length);
執行以上代碼,輸出結果爲:
buffer length: 14
Stream 是一個抽象接口,Node 中有不少對象實現了這個接口。例如,對http 服務器發起請求的request 對象就是一個 Stream,還有stdout(標準輸出)。
Node.js,Stream 有四種流類型:
全部的 Stream 對象都是 EventEmitter 的實例。經常使用的事件有:
本教程會爲你們介紹經常使用的流操做。
建立 input.txt 文件,內容以下:
菜鳥教程官網地址:www.runoob.com
建立 main.js 文件, 代碼以下:
var fs = require("fs");
var data = '';
// 建立可讀流
var readerStream = fs.createReadStream('input.txt');
// 設置編碼爲 utf8。
readerStream.setEncoding('UTF8');
// 處理流事件 --> data, end, and error
readerStream.on('data', function(chunk) {
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序執行完畢");
以上代碼執行結果以下:
程序執行完畢
菜鳥教程官網地址:www.runoob.com
建立 main.js 文件, 代碼以下:
var fs = require("fs");
var data = '菜鳥教程官網地址:www.runoob.com';
// 建立一個能夠寫入的流,寫入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 編碼寫入數據
writerStream.write(data,'UTF8');
// 標記文件末尾
writerStream.end();
// 處理流事件 --> data, end, and error
writerStream.on('finish', function() {
console.log("寫入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序執行完畢");
以上程序會將 data 變量的數據寫入到 output.txt 文件中。代碼執行結果以下:
$ node main.js
程序執行完畢
寫入完成。
查看 output.txt 文件的內容:
$ cat output.txt
菜鳥教程官網地址:www.runoob.com
管道提供了一個輸出流到輸入流的機制。一般咱們用於從一個流中獲取數據並將數據傳遞到另一個流中。
如上面的圖片所示,咱們把文件比做裝水的桶,而水就是文件裏的內容,咱們用一根管子(pipe)鏈接兩個桶使得水從一個桶流入另外一個桶,這樣就慢慢的實現了大文件的複製過程。
如下實例咱們經過讀取一個文件內容並將內容寫入到另一個文件中。
設置 input.txt 文件內容以下:
菜鳥教程官網地址:www.runoob.com
管道流操做實例
建立 main.js 文件, 代碼以下:
var fs = require("fs");
// 建立一個可讀流
var readerStream = fs.createReadStream('input.txt');
// 建立一個可寫流
var writerStream = fs.createWriteStream('output.txt');
// 管道讀寫操做
// 讀取 input.txt 文件內容,並將內容寫入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log("程序執行完畢");
代碼執行結果以下:
$ node main.js
程序執行完畢
查看 output.txt 文件的內容:
$ cat output.txt
菜鳥教程官網地址:www.runoob.com
管道流操做實例
鏈式是經過鏈接輸出流到另一個流並建立多個流操做鏈的機制。鏈式流通常用於管道操做。
接下來咱們就是用管道和鏈式來壓縮和解壓文件。
建立 compress.js 文件, 代碼以下:
var fs = require("fs");
var zlib = require('zlib');
// 壓縮 input.txt 文件爲 input.txt.gz
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件壓縮完成。");
代碼執行結果以下:
$ node compress.js
文件壓縮完成。
執行完以上操做後,咱們能夠看到當前目錄下生成了 input.txt 的壓縮文件 input.txt.gz。
接下來,讓咱們來解壓該文件,建立 decompress.js 文件,代碼以下:
var fs = require("fs");
var zlib = require('zlib');
// 解壓 input.txt.gz 文件爲 input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("文件解壓完成。");
代碼執行結果以下:
$ node decompress.js
文件解壓完成。
爲了讓Node.js的文件能夠相互調用,Node.js提供了一個簡單的模塊系統。
模塊是Node.js 應用程序的基本組成部分,文件和模塊是一一對應的。換言之,一個 Node.js 文件就是一個模塊,這個文件多是JavaScript 代碼、JSON 或者編譯過的C/C++ 擴展。
在 Node.js 中,建立一個模塊很是簡單,以下咱們建立一個 main.js 文件,代碼以下:
var hello = require('./hello');
hello.world();
以上實例中,代碼 require('./hello') 引入了當前目錄下的 hello.js 文件(./ 爲當前目錄,node.js 默認後綴爲 js)。
Node.js 提供了 exports 和 require 兩個對象,其中 exports 是模塊公開的接口,require 用於從外部獲取一個模塊的接口,即所獲取模塊的 exports 對象。
接下來咱們就來建立 hello.js 文件,代碼以下:
exports.world = function() {
console.log('Hello World');
}
在以上示例中,hello.js 經過 exports 對象把 world 做爲模塊的訪問接口,在 main.js 中經過 require('./hello') 加載這個模塊,而後就能夠直接訪 問 hello.js 中 exports 對象的成員函數了。
有時候咱們只是想把一個對象封裝到模塊中,格式以下:
module.exports = function() {
// ...
}
例如:
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello;
這樣就能夠直接得到這個對象了:
//main.js
var Hello = require('./hello');
hello = new Hello();
hello.setName('BYVoid');
hello.sayHello();
模塊接口的惟一變化是使用 module.exports = Hello 代替了exports.world = function(){}。 在外部引用該模塊時,其接口對象就是要輸出的 Hello 對象自己,而不是原先的 exports。
也許你已經注意到,咱們已經在代碼中使用了模塊了。像這樣:
var http = require("http");
...
http.createServer(...);
Node.js 中自帶了一個叫作 http 的模塊,咱們在咱們的代碼中請求它並把返回值賦給一個本地變量。
這把咱們的本地變量變成了一個擁有全部 http 模塊所提供的公共方法的對象。
Node.js 的 require 方法中的文件查找策略以下:
因爲 Node.js 中存在 4 類模塊(原生模塊和3種文件模塊),儘管 require 方法極其簡單,可是內部的加載倒是十分複雜的,其加載優先級也各自不一樣。以下圖所示:
儘管原生模塊與文件模塊的優先級不一樣,可是都會優先從文件模塊的緩存中加載已經存在的模塊。
原生模塊的優先級僅次於文件模塊緩存的優先級。require 方法在解析文件名以後,優先檢查模塊是否在原生模塊列表中。以http模塊爲例,儘管在目錄下存在一個 http/http.js/http.node/http.json 文件,require("http") 都不會從這些文件中加載,而是從原生模塊中加載。
原生模塊也有一個緩存區,一樣也是優先從緩存區加載。若是緩存區沒有被加載過,則調用原生模塊的加載方式進行加載和執行。
當文件模塊緩存中不存在,並且不是原生模塊的時候,Node.js 會解析 require 方法傳入的參數,並從文件系統中加載實際的文件,加載過程當中的包裝和編譯細節在前一節中已經介紹過,這裏咱們將詳細描述查找文件模塊的過程,其中,也有一些細節值得知曉。
require方法接受如下幾種參數的傳遞:
在路徑 Y 下執行 require(X) 語句執行順序:
1. 若是 X 是內置模塊
a. 返回內置模塊
b. 中止執行
2. 若是 X 以 '/' 開頭
a. 設置 Y 爲文件根路徑
3. 若是 X 以 './' 或 '/' or '../' 開頭
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
4. LOAD_NODE_MODULES(X, dirname(Y))
5. 拋出異常 "not found"
LOAD_AS_FILE(X)
1. 若是 X 是一個文件, 將 X 做爲 JavaScript 文本載入並中止執行。
2. 若是 X.js 是一個文件, 將 X.js 做爲 JavaScript 文本載入並中止執行。
3. 若是 X.json 是一個文件, 解析 X.json 爲 JavaScript 對象並中止執行。
4. 若是 X.node 是一個文件, 將 X.node 做爲二進制插件載入並中止執行。
LOAD_INDEX(X)
1. 若是 X/index.js 是一個文件, 將 X/index.js 做爲 JavaScript 文本載入並中止執行。
2. 若是 X/index.json 是一個文件, 解析 X/index.json 爲 JavaScript 對象並中止執行。
3. 若是 X/index.node 是一個文件, 將 X/index.node 做爲二進制插件載入並中止執行。
LOAD_AS_DIRECTORY(X)
1. 若是 X/package.json 是一個文件,
a. 解析 X/package.json, 並查找 "main" 字段。
b. let M = X + (json main 字段)
c. LOAD_AS_FILE(M)
d. LOAD_INDEX(M)
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let I = count of PARTS - 1
3. let DIRS = []
4. while I >= 0,
a. if PARTS[I] = "node_modules" CONTINUE
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIRS + DIR
d. let I = I - 1
5. return DIRS
在JavaScript中,一個函數能夠做爲另外一個函數的參數。咱們能夠先定義一個函數,而後傳遞,也能夠在傳遞參數的地方直接定義函數。
Node.js中函數的使用與Javascript相似,舉例來講,你能夠這樣作:
function say(word) {
console.log(word);
}
function execute(someFunction, value) {
someFunction(value);
}
execute(say, "Hello");
以上代碼中,咱們把 say 函數做爲execute函數的第一個變量進行了傳遞。這裏傳遞的不是 say 的返回值,而是 say 自己!
這樣一來, say 就變成了execute 中的本地變量 someFunction ,execute能夠經過調用 someFunction() (帶括號的形式)來使用 say 函數。
固然,由於 say 有一個變量, execute 在調用 someFunction 時能夠傳遞這樣一個變量。
咱們能夠把一個函數做爲變量傳遞。可是咱們不必定要繞這個"先定義,再傳遞"的圈子,咱們能夠直接在另外一個函數的括號中定義和傳遞這個函數:
function execute(someFunction, value) {
someFunction(value);
}
execute(function(word){ console.log(word) }, "Hello");
咱們在 execute 接受第一個參數的地方直接定義了咱們準備傳遞給 execute 的函數。
用這種方式,咱們甚至不用給這個函數起名字,這也是爲何它被叫作匿名函數 。
帶着這些知識,咱們再來看看咱們簡約而不簡單的HTTP服務器:
var http = require("http");
http.createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);
如今它看上去應該清晰了不少:咱們向 createServer 函數傳遞了一個匿名函數。
用這樣的代碼也能夠達到一樣的目的:
var http = require("http");
function onRequest(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
咱們要爲路由提供請求的 URL 和其餘須要的 GET 及 POST 參數,隨後路由須要根據這些數據來執行相應的代碼。
所以,咱們須要查看 HTTP 請求,從中提取出請求的 URL 以及 GET/POST 參數。這一功能應當屬於路由仍是服務器(甚至做爲一個模塊自身的功能)確實值得探討,但這裏暫定其爲咱們的HTTP服務器的功能。
咱們須要的全部數據都會包含在 request 對象中,該對象做爲 onRequest() 回調函數的第一個參數傳遞。可是爲了解析這些數據,咱們須要額外的 Node.JS 模塊,它們分別是 url 和 querystring 模塊。
url.parse(string).query
|
url.parse(string).pathname |
| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring.parse(queryString)["foo"] |
|
querystring.parse(queryString)["hello"]
固然咱們也能夠用 querystring 模塊來解析 POST 請求體中的參數,稍後會有演示。
如今咱們來給 onRequest() 函數加上一些邏輯,用來找出瀏覽器請求的 URL 路徑:
var http = require("http");
var url = require("url");
function start() { function onRequest(request, response) {
var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end(); }
http.createServer(onRequest).listen(8888);
console.log("Server has started."); }
exports.start = start;
好了,咱們的應用如今能夠經過請求的 URL 路徑來區別不一樣請求了--這使咱們得以使用路由(還未完成)來將請求以 URL 路徑爲基準映射處處理程序上。
在咱們所要構建的應用中,這意味着來自 /start 和 /upload 的請求可使用不一樣的代碼來處理。稍後咱們將看到這些內容是如何整合到一塊兒的。
如今咱們能夠來編寫路由了,創建一個名爲 router.js 的文件,添加如下內容:
function route(pathname) { console.log("About to route a request for " + pathname); } exports.route = route;
如你所見,這段代碼什麼也沒幹,不過對於如今來講這是應該的。在添加更多的邏輯之前,咱們先來看看如何把路由和服務器整合起來。
咱們的服務器應當知道路由的存在並加以有效利用。咱們固然能夠經過硬編碼的方式將這一依賴項綁定到服務器上,可是其它語言的編程經驗告訴咱們這會是一件很是痛苦的事,所以咱們將使用依賴注入的方式較鬆散地添加路由模塊。
首先,咱們來擴展一下服務器的 start() 函數,以便將路由函數做爲參數傳遞過去,server.js 文件代碼以下
var http = require("http"); var url = require("url"); function start(route) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received."); route(pathname); response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); } http.createServer(onRequest).listen(8888); console.log("Server has started."); } exports.start = start;
同時,咱們會相應擴展 index.js,使得路由函數能夠被注入到服務器中:
var server = require("./server"); var router = require("./router"); server.start(router.route);
在這裏,咱們傳遞的函數依舊什麼也沒作。
若是如今啓動應用(node index.js,始終記得這個命令行),隨後請求一個URL,你將會看到應用輸出相應的信息,這代表咱們的HTTP服務器已經在使用路由模塊了,並會將請求的路徑傳遞給路由:
$ node index.js
Server has started.
以上輸出已經去掉了比較煩人的 /favicon.ico 請求相關的部分。
瀏覽器訪問 http://127.0.0.1:8888/,輸出結果以下:
JavaScript 中有一個特殊的對象,稱爲全局對象(Global Object),它及其全部屬性均可以在程序的任何地方訪問,即全局變量。
在瀏覽器 JavaScript 中,一般 window 是全局對象, 而 Node.js 中的全局對象是 global,全部全局變量(除了 global 自己之外)都是 global 對象的屬性。
在 Node.js 咱們能夠直接訪問到 global 的屬性,而不須要在應用中包含它。
global 最根本的做用是做爲全局變量的宿主。按照 ECMAScript 的定義,知足如下條 件的變量是全局變量:
當你定義一個全局變量時,這個變量同時也會成爲全局對象的屬性,反之亦然。須要注 意的是,在 Node.js 中你不可能在最外層定義變量,由於全部用戶代碼都是屬於當前模塊的, 而模塊自己不是最外層上下文。
注意: 永遠使用 var 定義變量以免引入全局變量,由於全局變量會污染 命名空間,提升代碼的耦合風險。
__filename 表示當前正在執行的腳本的文件名。它將輸出文件所在位置的絕對路徑,且和命令行參數所指定的文件名不必定相同。 若是在模塊中,返回的值是模塊文件的路徑。
建立文件 main.js ,代碼以下所示:
// 輸出全局變量 __filename 的值
console.log( __filename );
執行 main.js 文件,代碼以下所示:
$ node main.js
/web/com/runoob/nodejs/main.js
__dirname 表示當前執行腳本所在的目錄。
建立文件 main.js ,代碼以下所示:
// 輸出全局變量 __dirname 的值
console.log( __dirname );
執行 main.js 文件,代碼以下所示:
$ node main.js
/web/com/runoob/nodejs
setTimeout(cb, ms) 全局函數在指定的毫秒(ms)數後執行指定函數(cb)。:setTimeout() 只執行一次指定函數。
返回一個表明定時器的句柄值。
建立文件 main.js ,代碼以下所示:
function printHello(){
console.log( "Hello, World!");
}
// 兩秒後執行以上函數
setTimeout(printHello, 2000);
執行 main.js 文件,代碼以下所示:
$ node main.js
Hello, World!
clearTimeout( t ) 全局函數用於中止一個以前經過 setTimeout() 建立的定時器。 參數 t 是經過 setTimeout() 函數建立的定時器。
建立文件 main.js ,代碼以下所示:
function printHello(){
console.log( "Hello, World!");
}
// 兩秒後執行以上函數
var t = setTimeout(printHello, 2000);
// 清除定時器
clearTimeout(t);
執行 main.js 文件,代碼以下所示:
$ node main.js
setInterval(cb, ms) 全局函數在指定的毫秒(ms)數後執行指定函數(cb)。
返回一個表明定時器的句柄值。可使用 clearInterval(t) 函數來清除定時器。
setInterval() 方法會不停地調用函數,直到 clearInterval() 被調用或窗口被關閉。
建立文件 main.js ,代碼以下所示:
function printHello(){
console.log( "Hello, World!");
}
// 兩秒後執行以上函數
setInterval(printHello, 2000);
執行 main.js 文件,代碼以下所示:
$ node main.js
Hello, World! Hello, World! Hello, World! Hello, World! Hello, World! ……
以上程序每隔兩秒就會輸出一次"Hello, World!",且會永久執行下去,直到你按下 ctrl + c 按鈕。
console 用於提供控制檯標準輸出,它是由 Internet Explorer 的 JScript 引擎提供的調試工具,後來逐漸成爲瀏覽器的實施標準。
Node.js 沿用了這個標準,提供與習慣行爲一致的 console 對象,用於向標準輸出流(stdout)或標準錯誤流(stderr)輸出字符。
如下爲 console 對象的方法:
序號 |
方法 & 描述 |
1 |
console.log([data][, ...]) |
2 |
console.info([data][, ...]) |
3 |
console.error([data][, ...]) |
4 |
console.warn([data][, ...]) |
5 |
console.dir(obj[, options]) |
6 |
console.time(label) |
7 |
console.timeEnd(label) |
8 |
console.trace(message[, ...]) |
9 |
console.assert(value[, message][, ...]) |
console.log():向標準輸出流打印字符並以換行符結束。
console.log 接收若干 個參數,若是隻有一個參數,則輸出這個參數的字符串形式。若是有多個參數,則 以相似於C 語言 printf() 命令的格式輸出。
第一個參數是一個字符串,若是沒有 參數,只打印一個換行。
console.log('Hello world');
console.log('byvoid%diovyb');
console.log('byvoid%diovyb', 1991);
運行結果爲:
Hello world
byvoid%diovyb
byvoid1991iovyb
console.trace();
運行結果爲:
Trace:
at Object.<anonymous> (/home/byvoid/consoletrace.js:1:71)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
建立文件 main.js ,代碼以下所示:
console.info("程序開始執行:");
var counter = 10;
console.log("計數: %d", counter);
console.time("獲取數據");
//
// 執行一些代碼
//
console.timeEnd('獲取數據');
console.info("程序執行完畢。")
執行 main.js 文件,代碼以下所示:
$ node main.js
程序開始執行:
計數: 10
獲取數據: 0ms
程序執行完畢
process 是一個全局變量,即 global 對象的屬性。
它用於描述當前Node.js 進程狀態的對象,提供了一個與操做系統的簡單接口。一般在你寫本地命令行程序的時候,少不了要 和它打交道。下面將會介紹 process 對象的一些最經常使用的成員方法。
序號 |
事件 & 描述 |
1 |
exit |
2 |
beforeExit |
3 |
uncaughtException |
4 |
Signal 事件 |
建立文件 main.js ,代碼以下所示:
process.on('exit', function(code) {
// 如下代碼永遠不會執行
setTimeout(function() {
console.log("該代碼不會執行");
}, 0);
console.log('退出碼爲:', code);
});
console.log("程序執行結束");
執行 main.js 文件,代碼以下所示:
$ node main.js
程序執行結束
退出碼爲: 0
退出狀態碼以下所示:
狀態碼 |
名稱 & 描述 |
1 |
Uncaught Fatal Exception |
2 |
Unused |
3 |
Internal JavaScript Parse Error |
4 |
Internal JavaScript Evaluation Failure |
5 |
Fatal Error |
6 |
Non-function Internal Exception Handler |
7 |
Internal Exception Handler Run-Time Failure |
8 |
Unused |
9 |
Invalid Argument |
10 |
Internal JavaScript Run-Time Failure |
12 |
Invalid Debug Argument |
128 |
Signal Exits |
Process 提供了不少有用的屬性,便於咱們更好的控制系統的交互:
序號. |
屬性 & 描述 |
1 |
stdout |
2 |
stderr |
3 |
stdin |
4 |
argv |
5 |
execPath |
6 |
execArgv |
7 |
env |
8 |
exitCode |
9 |
version |
10 |
versions |
11 |
config |
12 |
pid |
13 |
title |
14 |
arch |
15 |
platform |
16 |
mainModule |
建立文件 main.js ,代碼以下所示:
// 輸出到終端
process.stdout.write("Hello World!" + "\n");
// 經過參數讀取
process.argv.forEach(function(val, index, array) {
console.log(index + ': ' + val);
});
// 獲取執行路徑
console.log(process.execPath);
// 平臺信息
console.log(process.platform);
執行 main.js 文件,代碼以下所示:
$ node main.js
Hello World!
0: node
1: /web/www/node/main.js
/usr/local/node/0.10.36/bin/node
darwin
Process 提供了不少有用的方法,便於咱們更好的控制系統的交互:
序號 |
方法 & 描述 |
1 |
abort() |
2 |
chdir(directory) |
3 |
cwd() |
4 |
exit([code]) |
5 |
getgid() |
6 |
setgid(id) |
7 |
getuid() |
8 |
setuid(id) |
9 |
getgroups() |
10 |
setgroups(groups) |
11 |
initgroups(user, extra_group) |
12 |
kill(pid[, signal]) |
13 |
memoryUsage() |
14 |
nextTick(callback) |
15 |
umask([mask]) |
16 |
uptime() |
17 |
hrtime() |
建立文件 main.js ,代碼以下所示:
// 輸出當前目錄
console.log('當前目錄: ' + process.cwd());
// 輸出當前版本
console.log('當前版本: ' + process.version);
// 輸出內存使用狀況
console.log(process.memoryUsage());
執行 main.js 文件,代碼以下所示:
$ node main.js
當前目錄: /web/com/runoob/nodejs
當前版本: v0.10.36
{ rss: 12541952, heapTotal: 4083456, heapUsed: 2157056 }
util 是一個Node.js 核心模塊,提供經常使用函數的集合,用於彌補核心JavaScript 的功能 過於精簡的不足。
util.inherits(constructor, superConstructor)是一個實現對象間原型繼承 的函數。
JavaScript 的面向對象特性是基於原型的,與常見的基於類的不一樣。JavaScript 沒有 提供對象繼承的語言級別特性,而是經過原型複製來實現的。
在這裏咱們只介紹util.inherits 的用法,示例以下:
var util = require('util');
function Base() {
this.name = 'base';
this.base = 1991;
this.sayHello = function() {
console.log('Hello ' + this.name);
};
}
Base.prototype.showName = function() {
console.log(this.name);
};
function Sub() {
this.name = 'sub';
}
util.inherits(Sub, Base);
var objBase = new Base();
objBase.showName();
objBase.sayHello();
console.log(objBase);
var objSub = new Sub();
objSub.showName();
//objSub.sayHello();
console.log(objSub);
咱們定義了一個基礎對象Base 和一個繼承自Base 的Sub,Base 有三個在構造函數 內定義的屬性和一個原型中定義的函數,經過util.inherits 實現繼承。運行結果以下:
base
Hello base
{ name: 'base', base: 1991, sayHello: [Function] }
sub
{ name: 'sub' }
注意:Sub 僅僅繼承了Base 在原型中定義的函數,而構造函數內部創造的 base 屬 性和 sayHello 函數都沒有被 Sub 繼承。
同時,在原型中定義的屬性不會被console.log 做 爲對象的屬性輸出。若是咱們去掉 objSub.sayHello(); 這行的註釋,將會看到:
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Object #<Sub> has no method 'sayHello'
at Object.<anonymous> (/home/byvoid/utilinherits.js:29:8)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
at Array.0 (module.js:479:10)
at EventEmitter._tickCallback (node.js:192:40)
util.inspect(object,[showHidden],[depth],[colors])是一個將任意對象轉換 爲字符串的方法,一般用於調試和錯誤輸出。它至少接受一個參數 object,即要轉換的對象。
showHidden 是一個可選參數,若是值爲 true,將會輸出更多隱藏信息。
depth 表示最大遞歸的層數,若是對象很複雜,你能夠指定層數以控制輸出信息的多 少。若是不指定depth,默認會遞歸2層,指定爲 null 表示將不限遞歸層數完整遍歷對象。 若是color 值爲 true,輸出格式將會以ANSI 顏色編碼,一般用於在終端顯示更漂亮 的效果。
特別要指出的是,util.inspect 並不會簡單地直接把對象轉換爲字符串,即便該對 象定義了toString 方法也不會調用。
var util = require('util');
function Person() {
this.name = 'byvoid';
this.toString = function() {
return this.name;
};
}
var obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj, true));
運行結果是:
Person { name: 'byvoid', toString: [Function] }
Person {
name: 'byvoid',
toString:
{ [Function]
[length]: 0,
[name]: '',
[arguments]: null,
[caller]: null,
[prototype]: { [constructor]: [Circular] } } }
若是給定的參數 "object" 是一個數組返回true,不然返回false。
var util = require('util');
util.isArray([])
// true
util.isArray(new Array)
// true
util.isArray({})
// false
若是給定的參數 "object" 是一個正則表達式返回true,不然返回false。
var util = require('util');
util.isRegExp(/some regexp/)
// true
util.isRegExp(new RegExp('another regexp'))
// true
util.isRegExp({})
// false
若是給定的參數 "object" 是一個日期返回true,不然返回false。
var util = require('util');
util.isDate(new Date())
// true
util.isDate(Date())
// false (without 'new' returns a String)
util.isDate({})
// false
若是給定的參數 "object" 是一個錯誤對象返回true,不然返回false。
var util = require('util');
util.isError(new Error())
// true
util.isError(new TypeError())
// true
util.isError({ name: 'Error', message: 'an error occurred' })
// false
Node.js 提供一組相似 UNIX(POSIX)標準的文件操做API。 Node 導入文件系統模塊(fs)語法以下所示:
var fs = require("fs")
Node.js 文件系統(fs 模塊)模塊中的方法均有異步和同步版本,例如讀取文件內容的函數有異步的 fs.readFile() 和同步的 fs.readFileSync()。
異步的方法函數最後一個參數爲回調函數,回調函數的第一個參數包含了錯誤信息(error)。
建議你們使用異步方法,比起同步,異步方法性能更高,速度更快,並且沒有阻塞。
建立 input.txt 文件,內容以下:
菜鳥教程官網地址:www.runoob.com
文件讀取實例
建立 file.js 文件, 代碼以下:
var fs = require("fs");
// 異步讀取
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("異步讀取: " + data.toString());
});
// 同步讀取
var data = fs.readFileSync('input.txt');
console.log("同步讀取: " + data.toString());
console.log("程序執行完畢。");
以上代碼執行結果以下:
$ node file.js
同步讀取: 菜鳥教程官網地址:www.runoob.com
文件讀取實例
程序執行完畢。
異步讀取: 菜鳥教程官網地址:www.runoob.com
文件讀取實例
接下來,讓咱們來具體瞭解下 Node.js 文件系統的方法。
如下爲在異步模式下打開文件的語法格式:
fs.open(path, flags[, mode], callback)
參數使用說明以下:
flags 參數能夠是如下值:
Flag |
描述 |
r |
以讀取模式打開文件。若是文件不存在拋出異常。 |
r+ |
以讀寫模式打開文件。若是文件不存在拋出異常。 |
rs |
以同步的方式讀取文件。 |
rs+ |
以同步的方式讀取和寫入文件。 |
w |
以寫入模式打開文件,若是文件不存在則建立。 |
wx |
相似 'w',可是若是文件路徑存在,則文件寫入失敗。 |
w+ |
以讀寫模式打開文件,若是文件不存在則建立。 |
wx+ |
相似 'w+', 可是若是文件路徑存在,則文件讀寫失敗。 |
a |
以追加模式打開文件,若是文件不存在則建立。 |
ax |
相似 'a', 可是若是文件路徑存在,則文件追加失敗。 |
a+ |
以讀取追加模式打開文件,若是文件不存在則建立。 |
ax+ |
相似 'a+', 可是若是文件路徑存在,則文件讀取追加失敗。 |
接下來咱們建立 file.js 文件,並打開 input.txt 文件進行讀寫,代碼以下所示:
var fs = require("fs");
// 異步打開文件
console.log("準備打開文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開成功!");
});
以上代碼執行結果以下:
$ node file.js
準備打開文件!
文件打開成功!
如下爲經過異步模式獲取文件信息的語法格式:
fs.stat(path, callback)
參數使用說明以下:
fs.stat(path)執行後,會將stats類的實例返回給其回調函數。能夠經過stats類中的提供方法判斷文件的相關屬性。例如判斷是否爲文件:
var fs = require('fs');
fs.stat('/Users/liuht/code/itbilu/demo/fs.js', function (err, stats) {
console.log(stats.isFile()); //true
})
stats類中的方法有:
方法 |
描述 |
stats.isFile() |
若是是文件返回 true,不然返回 false。 |
stats.isDirectory() |
若是是目錄返回 true,不然返回 false。 |
stats.isBlockDevice() |
若是是塊設備返回 true,不然返回 false。 |
stats.isCharacterDevice() |
若是是字符設備返回 true,不然返回 false。 |
stats.isSymbolicLink() |
若是是軟連接返回 true,不然返回 false。 |
stats.isFIFO() |
若是是FIFO,返回true,不然返回 false。FIFO是UNIX中的一種特殊類型的命令管道。 |
stats.isSocket() |
若是是 Socket 返回 true,不然返回 false。 |
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
console.log("準備打開文件!");
fs.stat('input.txt', function (err, stats) {
if (err) {
return console.error(err);
}
console.log(stats);
console.log("讀取文件信息成功!");
// 檢測文件類型
console.log("是否爲文件(isFile) ? " + stats.isFile());
console.log("是否爲目錄(isDirectory) ? " + stats.isDirectory());
});
以上代碼執行結果以下:
$ node file.js
準備打開文件!
{ dev: 16777220,
mode: 33188,
nlink: 1,
uid: 501,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 40333161,
size: 61,
blocks: 8,
atime: Mon Sep 07 2015 17:43:55 GMT+0800 (CST),
mtime: Mon Sep 07 2015 17:22:35 GMT+0800 (CST),
ctime: Mon Sep 07 2015 17:22:35 GMT+0800 (CST) }
讀取文件信息成功!
是否爲文件(isFile) ? true
是否爲目錄(isDirectory) ? false
如下爲異步模式下寫入文件的語法格式:
fs.writeFile(file, data[, options], callback)
writeFile 直接打開文件默認是 w 模式,因此若是文件存在,該方法寫入的內容會覆蓋舊的文件內容。
參數使用說明以下:
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
console.log("準備寫入文件");
fs.writeFile('input.txt', '我是通 過fs.writeFile 寫入文件的內容', function(err) {
if (err) {
return console.error(err);
}
console.log("數據寫入成功!");
console.log("--------我是分割線-------------")
console.log("讀取寫入的數據!");
fs.readFile('input.txt', function (err, data) {
if (err) {
return console.error(err);
}
console.log("異步讀取文件數據: " + data.toString());
});
});
以上代碼執行結果以下:
$ node file.js
準備寫入文件
數據寫入成功!
--------我是分割線-------------
讀取寫入的數據!
異步讀取文件數據: 我是通 過fs.writeFile 寫入文件的內容
如下爲異步模式下讀取文件的語法格式:
fs.read(fd, buffer, offset, length, position, callback)
該方法使用了文件描述符來讀取文件。
參數使用說明以下:
input.txt 文件內容爲:
菜鳥教程官網地址:www.runoob.com
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
var buf = new Buffer(1024);
console.log("準備打開已存在的文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開成功!");
console.log("準備讀取文件:");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
console.log(bytes + " 字節被讀取");
// 僅輸出讀取的字節
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
});
});
以上代碼執行結果以下:
$ node file.js
準備打開已存在的文件!
文件打開成功!
準備讀取文件:
42 字節被讀取
菜鳥教程官網地址:www.runoob.com
如下爲異步模式下關閉文件的語法格式:
fs.close(fd, callback)
該方法使用了文件描述符來讀取文件。
參數使用說明以下:
input.txt 文件內容爲:
菜鳥教程官網地址:www.runoob.com
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
var buf = new Buffer(1024);
console.log("準備打開文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開成功!");
console.log("準備讀取文件!");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
// 僅輸出讀取的字節
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
// 關閉文件
fs.close(fd, function(err){
if (err){
console.log(err);
}
console.log("文件關閉成功");
});
});
});
以上代碼執行結果以下:
$ node file.js
準備打開文件!
文件打開成功!
準備讀取文件!
菜鳥教程官網地址:www.runoob.com
文件關閉成功
如下爲異步模式下截取文件的語法格式:
fs.ftruncate(fd, len, callback)
該方法使用了文件描述符來讀取文件。
參數使用說明以下:
input.txt 文件內容爲:
site:www.runoob.com
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
var buf = new Buffer(1024);
console.log("準備打開文件!");
fs.open('input.txt', 'r+', function(err, fd) {
if (err) {
return console.error(err);
}
console.log("文件打開成功!");
console.log("截取了10字節後的文件內容。");
// 截取文件
fs.ftruncate(fd, 10, function(err){
if (err){
console.log(err);
}
console.log("文件截取成功。");
console.log("讀取相同的文件");
fs.read(fd, buf, 0, buf.length, 0, function(err, bytes){
if (err){
console.log(err);
}
// 僅輸出讀取的字節
if(bytes > 0){
console.log(buf.slice(0, bytes).toString());
}
// 關閉文件
fs.close(fd, function(err){
if (err){
console.log(err);
}
console.log("文件關閉成功!");
});
});
});
});
以上代碼執行結果以下:
$ node file.js
準備打開文件!
文件打開成功!
截取了10字節後的文件內容。
文件截取成功。
讀取相同的文件
site:www.r
文件關閉成功
如下爲刪除文件的語法格式:
fs.unlink(path, callback)
參數使用說明以下:
input.txt 文件內容爲:
site:www.runoob.com
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
console.log("準備刪除文件!");
fs.unlink('input.txt', function(err) {
if (err) {
return console.error(err);
}
console.log("文件刪除成功!");
});
以上代碼執行結果以下:
$ node file.js
準備刪除文件!
文件刪除成功!
再去查看 input.txt 文件,發現已經不存在了。
如下爲建立目錄的語法格式:
fs.mkdir(path[, mode], callback)
參數使用說明以下:
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
console.log("建立目錄 /tmp/test/");
fs.mkdir("/tmp/test/",function(err){
if (err) {
return console.error(err);
}
console.log("目錄建立成功。");
});
以上代碼執行結果以下:
$ node file.js
建立目錄 /tmp/test/
目錄建立成功。
如下爲讀取目錄的語法格式:
fs.readdir(path, callback)
參數使用說明以下:
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
console.log("查看 /tmp 目錄");
fs.readdir("/tmp/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
以上代碼執行結果以下:
$ node file.js
查看 /tmp 目錄
input.out
output.out
test
test.txt
如下爲刪除目錄的語法格式:
fs.rmdir(path, callback)
參數使用說明以下:
接下來咱們建立 file.js 文件,代碼以下所示:
var fs = require("fs");
// 執行前建立一個空的 /tmp/test 目錄
console.log("準備刪除目錄 /tmp/test");
fs.rmdir("/tmp/test",function(err){
if (err) {
return console.error(err);
}
console.log("讀取 /tmp 目錄");
fs.readdir("/tmp/",function(err, files){
if (err) {
return console.error(err);
}
files.forEach( function (file){
console.log( file );
});
});
});
以上代碼執行結果以下:
$ node file.js
準備刪除目錄 /tmp/test
讀取 /tmp 目錄
……
如下爲 Node.js 文件模塊相同的方法列表:
序號 |
方法 & 描述 |
1 |
fs.rename(oldPath, newPath, callback) |
2 |
fs.ftruncate(fd, len, callback) |
3 |
fs.ftruncateSync(fd, len) |
4 |
fs.truncate(path, len, callback) |
5 |
fs.truncateSync(path, len) |
6 |
fs.chown(path, uid, gid, callback) |
7 |
fs.chownSync(path, uid, gid) |
8 |
fs.fchown(fd, uid, gid, callback) |
9 |
fs.fchownSync(fd, uid, gid) |
10 |
fs.lchown(path, uid, gid, callback) |
11 |
fs.lchownSync(path, uid, gid) |
12 |
fs.chmod(path, mode, callback) |
13 |
fs.chmodSync(path, mode) |
14 |
fs.fchmod(fd, mode, callback) |
15 |
fs.fchmodSync(fd, mode) |
16 |
fs.lchmod(path, mode, callback) |
17 |
fs.lchmodSync(path, mode) |
18 |
fs.stat(path, callback) |
19 |
fs.lstat(path, callback) |
20 |
fs.fstat(fd, callback) |
21 |
fs.statSync(path) |
22 |
fs.lstatSync(path) |
23 |
fs.fstatSync(fd) |
24 |
fs.link(srcpath, dstpath, callback) |
25 |
fs.linkSync(srcpath, dstpath) |
26 |
fs.symlink(srcpath, dstpath[, type], callback) |
27 |
fs.symlinkSync(srcpath, dstpath[, type]) |
28 |
fs.readlink(path, callback) |
29 |
fs.realpath(path[, cache], callback) |
30 |
fs.realpathSync(path[, cache]) |
31 |
fs.unlink(path, callback) |
32 |
fs.unlinkSync(path) |
33 |
fs.rmdir(path, callback) |
34 |
fs.rmdirSync(path) |
35 |
fs.mkdir(path[, mode], callback) |
36 |
fs.mkdirSync(path[, mode]) |
37 |
fs.readdir(path, callback) |
38 |
fs.readdirSync(path) |
39 |
fs.close(fd, callback) |
40 |
fs.closeSync(fd) |
41 |
fs.open(path, flags[, mode], callback) |
42 |
fs.openSync(path, flags[, mode]) |
43 |
fs.utimes(path, atime, mtime, callback) |
44 |
fs.utimesSync(path, atime, mtime) |
45 |
fs.futimes(fd, atime, mtime, callback) |
46 |
fs.futimesSync(fd, atime, mtime) |
47 |
fs.fsync(fd, callback) |
48 |
fs.fsyncSync(fd) |
49 |
fs.write(fd, buffer, offset, length[, position], callback) |
50 |
fs.write(fd, data[, position[, encoding]], callback) |
51 |
fs.writeSync(fd, buffer, offset, length[, position]) |
52 |
fs.writeSync(fd, data[, position[, encoding]]) |
53 |
fs.read(fd, buffer, offset, length, position, callback) |
54 |
fs.readSync(fd, buffer, offset, length, position) |
55 |
fs.readFile(filename[, options], callback) |
56 |
fs.readFileSync(filename[, options])<="" td=""> |
57 |
fs.writeFile(filename, data[, options], callback) |
58 |
fs.writeFileSync(filename, data[, options]) |
59 |
fs.appendFile(filename, data[, options], callback) |
60 |
fs.appendFileSync(filename, data[, options]) |
61 |
fs.watchFile(filename[, options], listener) |
62 |
fs.unwatchFile(filename[, listener]) |
63 |
fs.watch(filename[, options][, listener]) |
64 |
fs.exists(path, callback) |
65 |
fs.existsSync(path) |
66 |
fs.access(path[, mode], callback) |
67 |
fs.accessSync(path[, mode]) |
68 |
fs.createReadStream(path[, options]) |
69 |
fs.createWriteStream(path[, options]) |
70 |
fs.symlink(srcpath, dstpath[, type], callback) |
在不少場景中,咱們的服務器都須要跟用戶的瀏覽器打交道,如表單提交。
表單提交到服務器通常都使用 GET/POST 請求。
本章節咱們將爲你們介紹 Node.js GET/POS T請求。
因爲GET請求直接被嵌入在路徑中,URL是完整的請求路徑,包括了?後面的部分,所以你能夠手動解析後面的內容做爲GET請求的參數。
node.js 中 url 模塊中的 parse 函數提供了這個功能。
var http = require('http'); var url = require('url'); var util = require('util'); http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'}); res.end(util.inspect(url.parse(req.url, true))); }).listen(3000);
在瀏覽器中訪問 http://localhost:3000/user?name=菜鳥教程&url=www.runoob.com 而後查看返回結果:
咱們可使用 url.parse 方法來解析 URL 中的參數,代碼以下:
var http = require('http'); var url = require('url'); var util = require('util'); http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); // 解析 url 參數 var params = url.parse(req.url, true).query; res.write("網站名:" + params.name); res.write("\n"); res.write("網站 URL:" + params.url); res.end(); }).listen(3000);
在瀏覽器中訪問 http://localhost:3000/user?name=菜鳥教程&url=www.runoob.com 而後查看返回結果:
POST 請求的內容所有的都在請求體中,http.ServerRequest 並無一個屬性內容爲請求體,緣由是等待請求體傳輸多是一件耗時的工做。
好比上傳文件,而不少時候咱們可能並不須要理會請求體的內容,惡意的POST請求會大大消耗服務器的資源,因此 node.js 默認是不會解析請求體的,當你須要的時候,須要手動來作。
var http = require('http'); var querystring = require('querystring'); http.createServer(function(req, res){ // 定義了一個post變量,用於暫存請求體的信息 var post = ''; // 經過req的data事件監聽函數,每當接受到請求體的數據,就累加到post變量中 req.on('data', function(chunk){ post += chunk; }); // 在end事件觸發後,經過querystring.parse將post解析爲真正的POST請求格式,而後向客戶端返回。 req.on('end', function(){ post = querystring.parse(post); res.end(util.inspect(post)); }); }).listen(3000);
如下實例表單經過 POST 提交併輸出數據:
var http = require('http'); var querystring = require('querystring'); var postHTML = '<html><head><meta charset="utf-8"><title>菜鳥教程 Node.js 實例</title></head>' + '<body>' + '<form method="post">' + '網站名: <input name="name"><br>' + '網站 URL: <input name="url"><br>' + '<input type="submit">' + '</form>' + '</body></html>'; http.createServer(function (req, res) { var body = ""; req.on('data', function (chunk) { body += chunk; }); req.on('end', function () { // 解析參數 body = querystring.parse(body); // 設置響應頭部信息及編碼 res.writeHead(200, {'Content-Type': 'text/html; charset=utf8'}); if(body.name && body.url) { // 輸出提交的數據 res.write("網站名:" + body.name); res.write("<br>"); res.write("網站 URL:" + body.url); } else { // 輸出表單 res.write(postHTML); } res.end(); }); }).listen(3000);
執行結果 Gif 演示:
Web服務器通常指網站服務器,是指駐留於因特網上某種類型計算機的程序,Web服務器的基本功能就是提供Web信息瀏覽服務。它只需支持HTTP協議、HTML文檔格式及URL,與客戶端的網絡瀏覽器配合。
大多數 web 服務器都支持服務端的腳本語言(php、python、ruby)等,並經過腳本語言從數據庫獲取數據,將結果返回給客戶端瀏覽器。
目前最主流的三個Web服務器是Apache、Nginx、IIS。
Node.js 提供了 http 模塊,http 模塊主要用於搭建 HTTP 服務端和客戶端,使用 HTTP 服務器或客戶端功能必須調用 http 模塊,代碼以下:
var http = require('http');
如下是演示一個最基本的 HTTP 服務器架構(使用 8080 端口),建立 server.js 文件,代碼以下所示:
var http = require('http'); var fs = require('fs'); var url = require('url'); // 建立服務器 http.createServer( function (request, response) { // 解析請求,包括文件名 var pathname = url.parse(request.url).pathname; // 輸出請求的文件名 console.log("Request for " + pathname + " received."); // 從文件系統中讀取請求的文件內容 fs.readFile(pathname.substr(1), function (err, data) { if (err) { console.log(err); // HTTP 狀態碼: 404 : NOT FOUND // Content Type: text/plain response.writeHead(404, {'Content-Type': 'text/html'}); }else{ // HTTP 狀態碼: 200 : OK // Content Type: text/plain response.writeHead(200, {'Content-Type': 'text/html'}); // 響應文件內容 response.write(data.toString()); } // 發送響應數據 response.end(); }); }).listen(8080); // 控制檯會輸出如下信息 console.log('Server running at http://127.0.0.1:8080/');
接下來咱們在該目錄下建立一個 index.html 文件,代碼以下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>菜鳥教程(runoob.com)</title> </head> <body> <h1>個人第一個標題</h1> <p>個人第一個段落。</p> </body> </html>
執行 server.js 文件:
$ node server.js
Server running at http://127.0.0.1:8080/
接着咱們在瀏覽器中打開地址:http://127.0.0.1:8080/index.html,顯示以下圖所示:
執行 server.js 的控制檯輸出信息以下:
Server running at http://127.0.0.1:8080/
Request for /index.html received. # 客戶端請求信息
Node 建立 Web 客戶端須要引入 http 模塊,建立 client.js 文件,代碼以下所示:
var http = require('http'); // 用於請求的選項 var options = { host: 'localhost', port: '8080', path: '/index.html' }; // 處理響應的回調函數 var callback = function(response){ // 不斷更新數據 var body = ''; response.on('data', function(data) { body += data; }); response.on('end', function() { // 數據接收完成 console.log(body); }); } // 向服務端發送請求 var req = http.request(options, callback); req.end();
新開一個終端,執行 client.js 文件,輸出結果以下:
$ node client.js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com)</title>
</head>
<body>
<h1>個人第一個標題</h1>
<p>個人第一個段落。</p>
</body>
</html>
執行 server.js 的控制檯輸出信息以下:
Server running at http://127.0.0.1:8080/
Request for /index.html received. # 客戶端請求信息
Express 是一個簡潔而靈活的 node.js Web應用框架, 提供了一系列強大特性幫助你建立各類 Web 應用,和豐富的 HTTP 工具。
使用 Express 能夠快速地搭建一個完整功能的網站。
Express 框架核心特性:
安裝 Express 並將其保存到依賴列表中:
$ cnpm install express --save
以上命令會將 Express 框架安裝在當前目錄的 node_modules 目錄中, node_modules 目錄下會自動建立 express 目錄。如下幾個重要的模塊是須要與 express 框架一塊兒安裝的:
$ cnpm install body-parser --save
$ cnpm install cookie-parser --save
$ cnpm install multer --save
安裝完後,咱們能夠查看下 express 使用的版本號:
$ cnpm list express
/data/www/node
└── express@4.15.2 -> /Users/tianqixin/www/node/node_modules/.4.15.2@express
接下來咱們使用 Express 框架來輸出 "Hello World"。
如下實例中咱們引入了 express 模塊,並在客戶端發起請求後,響應 "Hello World" 字符串。
建立 express_demo.js 文件,代碼以下所示:
//express_demo.js 文件 var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello World'); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
$ node express_demo.js
應用實例,訪問地址爲 http://0.0.0.0:8081
在瀏覽器中訪問 http://127.0.0.1:8081,結果以下圖所示:
Express 應用使用回調函數的參數: request 和 response 對象來處理請求和響應的數據。
app.get('/', function (req, res) {
// --
})
request 和 response 對象的具體介紹:
Request 對象 - request 對象表示 HTTP 請求,包含了請求查詢字符串,參數,內容,HTTP 頭部等屬性。常見屬性有:
Response 對象 - response 對象表示 HTTP 響應,即在接收到請求時向客戶端發送的 HTTP 響應數據。常見屬性有:
咱們已經瞭解了 HTTP 請求的基本應用,而路由決定了由誰(指定腳本)去響應客戶端請求。
在HTTP請求中,咱們能夠經過路由提取出請求的URL以及GET/POST參數。
接下來咱們擴展 Hello World,添加一些功能來處理更多類型的 HTTP 請求。
建立 express_demo2.js 文件,代碼以下所示:
var express = require('express'); var app = express(); // 主頁輸出 "Hello World" app.get('/', function (req, res) { console.log("主頁 GET 請求"); res.send('Hello GET'); }) // POST 請求 app.post('/', function (req, res) { console.log("主頁 POST 請求"); res.send('Hello POST'); }) // /del_user 頁面響應 app.get('/del_user', function (req, res) { console.log("/del_user 響應 DELETE 請求"); res.send('刪除頁面'); }) // /list_user 頁面 GET 請求 app.get('/list_user', function (req, res) { console.log("/list_user GET 請求"); res.send('用戶列表頁面'); }) // 對頁面 abcd, abxcd, ab123cd, 等響應 GET 請求 app.get('/ab*cd', function(req, res) { console.log("/ab*cd GET 請求"); res.send('正則匹配'); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
$ node express_demo2.js
應用實例,訪問地址爲 http://0.0.0.0:8081
接下來你能夠嘗試訪問 http://127.0.0.1:8081 不一樣的地址,查看效果。
在瀏覽器中訪問 http://127.0.0.1:8081/list_user,結果以下圖所示:
在瀏覽器中訪問 http://127.0.0.1:8081/abcd,結果以下圖所示:
在瀏覽器中訪問 http://127.0.0.1:8081/abcdefg,結果以下圖所示:
Express 提供了內置的中間件 express.static 來設置靜態文件如:圖片, CSS, JavaScript 等。
你可使用 express.static 中間件來設置靜態文件路徑。例如,若是你將圖片, CSS, JavaScript 文件放在 public 目錄下,你能夠這麼寫:
app.use(express.static('public'));
咱們能夠到 public/images 目錄下放些圖片,以下所示:
項目路徑/public/images/logo.png
讓咱們再修改下 "Hello World" 應用添加處理靜態文件的功能。
建立 express_demo3.js 文件,代碼以下所示:
var express = require('express'); var app = express(); app.use(express.static('public')); app.get('/', function (req, res) { res.send('Hello World'); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
$ node express_demo3.js
應用實例,訪問地址爲 http://0.0.0.0:8081
執行以上代碼:
在瀏覽器中訪問 http://127.0.0.1:8081/images/logo.png(本實例採用了菜鳥教程的logo),結果以下圖所示:
如下實例演示了在表單中經過 GET 方法提交兩個參數,咱們可使用 server.js 文件內的 process_get 路由器來處理輸入:
<html> <body> <form action="http://127.0.0.1:8081/process_get" method="GET"> First Name: <input type="text" name="first_name"> <br> Last Name: <input type="text" name="last_name"> <input type="submit" value="Submit"> </form> </body> </html>
var express = require('express'); var app = express(); app.use(express.static('public')); app.get('/index.htm', function (req, res) { res.sendFile( __dirname + "/" + "index.htm" ); }) app.get('/process_get', function (req, res) { // 輸出 JSON 格式 var response = { "first_name":req.query.first_name, "last_name":req.query.last_name }; console.log(response); res.end(JSON.stringify(response)); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
瀏覽器訪問 http://127.0.0.1:8081/index.htm,如圖所示:
如今你能夠向表單輸入數據,並提交,以下演示:
如下實例演示了在表單中經過 POST 方法提交兩個參數,咱們可使用 server.js 文件內的 process_post 路由器來處理輸入:
<html> <body> <form action="http://127.0.0.1:8081/process_post" method="POST"> First Name: <input type="text" name="first_name"> <br> Last Name: <input type="text" name="last_name"> <input type="submit" value="Submit"> </form> </body> </html>
var express = require('express'); var app = express(); var bodyParser = require('body-parser'); // 建立 application/x-www-form-urlencoded 編碼解析 var urlencodedParser = bodyParser.urlencoded({ extended: false }) app.use(express.static('public')); app.get('/index.htm', function (req, res) { res.sendFile( __dirname + "/" + "index.htm" ); }) app.post('/process_post', urlencodedParser, function (req, res) { // 輸出 JSON 格式 var response = { "first_name":req.body.first_name, "last_name":req.body.last_name }; console.log(response); res.end(JSON.stringify(response)); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
瀏覽器訪問 http://127.0.0.1:8081/index.htm,如圖所示:
如今你能夠向表單輸入數據,並提交,以下演示:
如下咱們建立一個用於上傳文件的表單,使用 POST 方法,表單 enctype 屬性設置爲 multipart/form-data。
<html> <head> <title>文件上傳表單</title> </head> <body> <h3>文件上傳:</h3> 選擇一個文件上傳: <br /> <form action="/file_upload" method="post" enctype="multipart/form-data"> <input type="file" name="image" size="50" /> <br /> <input type="submit" value="上傳文件" /> </form> </body> </html>
var express = require('express'); var app = express(); var fs = require("fs"); var bodyParser = require('body-parser'); var multer = require('multer'); app.use(express.static('public')); app.use(bodyParser.urlencoded({ extended: false })); app.use(multer({ dest: '/tmp/'}).array('image')); app.get('/index.htm', function (req, res) { res.sendFile( __dirname + "/" + "index.htm" ); }) app.post('/file_upload', function (req, res) { console.log(req.files[0]); // 上傳的文件信息 var des_file = __dirname + "/" + req.files[0].originalname; fs.readFile( req.files[0].path, function (err, data) { fs.writeFile(des_file, data, function (err) { if( err ){ console.log( err ); }else{ response = { message:'File uploaded successfully', filename:req.files[0].originalname }; } console.log( response ); res.end( JSON.stringify( response ) ); }); }); }) var server = app.listen(8081, function () { var host = server.address().address var port = server.address().port console.log("應用實例,訪問地址爲 http://%s:%s", host, port) })
執行以上代碼:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
瀏覽器訪問 http://127.0.0.1:8081/index.htm,如圖所示:
如今你能夠向表單輸入數據,並提交,以下演示:
咱們可使用中間件向 Node.js 服務器發送 cookie 信息,如下代碼輸出了客戶端發送的 cookie 信息:
// express_cookie.js 文件 var express = require('express') var cookieParser = require('cookie-parser') var util = require('util'); var app = express() app.use(cookieParser()) app.get('/', function(req, res) { console.log("Cookies: " + util.inspect(req.cookies)); }) app.listen(8081)
執行以上代碼:
$ node express_cookie.js
如今你能夠訪問 http://127.0.0.1:8081 並查看終端信息的輸出,以下演示:
REST即表述性狀態傳遞(英文:Representational State Transfer,簡稱REST)是Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格。
表述性狀態轉移是一組架構約束條件和原則。知足這些約束條件和原則的應用程序或設計就是RESTful。須要注意的是,REST是設計風格而不是標準。REST一般基於使用HTTP,URI,和XML(標準通用標記語言下的一個子集)以及HTML(標準通用標記語言下的一個應用)這些現有的普遍流行的協議和標準。REST 一般使用 JSON 數據格式。
如下爲 REST 基本架構的四個方法:
Web service是一個平臺獨立的,低耦合的,自包含的、基於可編程的web的應用程序,可以使用開放的XML(標準通用標記語言下的一個子集)標準來描述、發佈、發現、協調和配置這些應用程序,用於開發分佈式的互操做的應用程序。
基於 REST 架構的 Web Services 便是 RESTful。
因爲輕量級以及經過 HTTP 直接傳輸數據的特性,Web 服務的 RESTful 方法已經成爲最多見的替代方法。可使用各類語言(好比 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])實現客戶端。
RESTful Web 服務一般能夠經過自動客戶端或表明用戶的應用程序訪問。可是,這種服務的簡便性讓用戶可以與之直接交互,使用它們的 Web 瀏覽器構建一個 GET URL 並讀取返回的內容。
更多介紹,能夠查看:RESTful 架構詳解
首先,建立一個 json 數據資源文件 users.json,內容以下:
{
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher",
"id": 1
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian",
"id": 2
},
"user3" : {
"name" : "ramesh",
"password" : "password3",
"profession" : "clerk",
"id": 3
}
}
基於以上數據,咱們建立如下 RESTful API:
序號 |
URI |
HTTP 方法 |
發送內容 |
結果 |
1 |
listUsers |
GET |
空 |
顯示全部用戶列表 |
2 |
addUser |
POST |
JSON 字符串 |
添加新用戶 |
3 |
deleteUser |
DELETE |
JSON 字符串 |
刪除用戶 |
4 |
:id |
GET |
空 |
顯示用戶詳細信息 |
如下代碼,咱們建立了 RESTful API listUsers,用於讀取用戶的信息列表, server.js 文件代碼以下所示:
var express = require('express');
var app = express();
var fs = require("fs");
app.get('/listUsers', function (req, res) {
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
console.log( data );
res.end( data );
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應用實例,訪問地址爲 http://%s:%s", host, port)
})
接下來執行如下命令:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
在瀏覽器中訪問 http://127.0.0.1:8081/listUsers,結果以下所示:
{
"user1" : {
"name" : "mahesh",
"password" : "password1",
"profession" : "teacher",
"id": 1
},
"user2" : {
"name" : "suresh",
"password" : "password2",
"profession" : "librarian",
"id": 2
},
"user3" : {
"name" : "ramesh",
"password" : "password3",
"profession" : "clerk",
"id": 3
}
}
如下代碼,咱們建立了 RESTful API addUser, 用於添加新的用戶數據,server.js 文件代碼以下所示:
var express = require('express');
var app = express();
var fs = require("fs");
//添加的新用戶數據
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.get('/addUser', function (req, res) {
// 讀取已存在的數據
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應用實例,訪問地址爲 http://%s:%s", host, port)
})
接下來執行如下命令:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
在瀏覽器中訪問 http://127.0.0.1:8081/addUser,結果以下所示:
{ user1:
{ name: 'mahesh',
password: 'password1',
profession: 'teacher',
id: 1 },
user2:
{ name: 'suresh',
password: 'password2',
profession: 'librarian',
id: 2 },
user3:
{ name: 'ramesh',
password: 'password3',
profession: 'clerk',
id: 3 },
user4:
{ name: 'mohit',
password: 'password4',
profession: 'teacher',
id: 4 }
}
如下代碼,咱們建立了 RESTful API :id(用戶id), 用於讀取指定用戶的詳細信息,server.js 文件代碼以下所示:
var express = require('express');
var app = express();
var fs = require("fs");
app.get('/:id', function (req, res) {
// 首先咱們讀取已存在的用戶
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
var user = data["user" + req.params.id]
console.log( user );
res.end( JSON.stringify(user));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應用實例,訪問地址爲 http://%s:%s", host, port)
})
接下來執行如下命令:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
在瀏覽器中訪問 http://127.0.0.1:8081/2,結果以下所示:
{
"name":"suresh",
"password":"password2",
"profession":"librarian",
"id":2
}
如下代碼,咱們建立了 RESTful API deleteUser, 用於刪除指定用戶的詳細信息,如下實例中,用戶 id 爲 2,server.js 文件代碼以下所示:
var express = require('express');
var app = express();
var fs = require("fs");
var id = 2;
app.get('/deleteUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
delete data["user" + 2];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("應用實例,訪問地址爲 http://%s:%s", host, port)
})
接下來執行如下命令:
$ node server.js
應用實例,訪問地址爲 http://0.0.0.0:8081
在瀏覽器中訪問 http://127.0.0.1:8081/deleteUser,結果以下所示:
{ user1:
{ name: 'mahesh',
password: 'password1',
profession: 'teacher',
id: 1 },
user3:
{ name: 'ramesh',
password: 'password3',
profession: 'clerk',
id: 3 }
}
本章節咱們將爲你們介紹如何使用 Node.js 來鏈接 MySQL,並對數據庫進行操做。
若是你尚未 MySQL 的基本知識,能夠參考咱們的教程:MySQL 教程。
本教程使用到的 Websites 表 SQL 文件:websites.sql。
本教程使用了淘寶定製的 cnpm 命令進行安裝:
$ cnpm install mysql
在如下實例中根據你的實際配置修改數據庫用戶名、及密碼及數據庫名:
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', database : 'test' }); connection.connect(); connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results[0].solution); });
執行如下命令輸出就結果爲:
$ node test.js
The solution is: 2
參數 |
描述 |
host |
主機地址 (默認:localhost) |
user |
用戶名 |
password |
密碼 |
port |
端口號 (默認:3306) |
database |
數據庫名 |
charset |
鏈接字符集(默認:'UTF8_GENERAL_CI',注意字符集的字母都要大寫) |
localAddress |
此IP用於TCP鏈接(可選) |
socketPath |
鏈接到unix域路徑,當使用 host 和 port 時會被忽略 |
timezone |
時區(默認:'local') |
connectTimeout |
鏈接超時(默認:不限制;單位:毫秒) |
stringifyObjects |
是否序列化對象 |
typeCast |
是否將列值轉化爲本地JavaScript類型值 (默認:true) |
queryFormat |
自定義query語句格式化方法 |
supportBigNumbers |
數據庫支持bigint或decimal類型列時,須要設此option爲true (默認:false) |
bigNumberStrings |
supportBigNumbers和bigNumberStrings啓用 強制bigint或decimal列以JavaScript字符串類型返回(默認:false) |
dateStrings |
強制timestamp,datetime,data類型以字符串類型返回,而不是JavaScript Date類型(默認:false) |
debug |
開啓調試(默認:false) |
multipleStatements |
是否許一個query中有多個MySQL語句 (默認:false) |
flags |
用於修改鏈接標誌 |
ssl |
使用ssl參數(與crypto.createCredenitals參數格式一至)或一個包含ssl配置文件名稱的字符串,目前只捆綁Amazon RDS的配置文件 |
更多說明可參見:https://github.com/mysqljs/mysql
在進行數據庫操做前,你須要將本站提供的 Websites 表 SQL 文件websites.sql 導入到你的 MySQL 數據庫中。
本教程測試的 MySQL 用戶名爲 root,密碼爲 123456,數據庫爲 test,你須要根據本身配置狀況修改。
將上面咱們提供的 SQL 文件導入數據庫後,執行如下代碼便可查詢出數據:
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();
執行如下命令輸出就結果爲:
$ node test.js
--------------------------SELECT----------------------------
[ RowDataPacket {
id: 1,
name: 'Google',
url: 'https://www.google.cm/',
alexa: 1,
country: 'USA' },
RowDataPacket {
id: 2,
name: '淘寶',
url: 'https://www.taobao.com/',
alexa: 13,
country: 'CN' },
RowDataPacket {
id: 3,
name: '菜鳥教程',
url: 'http://www.runoob.com/',
alexa: 4689,
country: 'CN' },
RowDataPacket {
id: 4,
name: '微博',
url: 'http://weibo.com/',
alexa: 20,
country: 'CN' },
RowDataPacket {
id: 5,
name: 'Facebook',
url: 'https://www.facebook.com/',
alexa: 3,
country: 'USA' } ]
------------------------------------------------------------
咱們能夠向數據表 websties 插入數據:
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)'; var addSqlParams = ['菜鳥工具', 'https://c.runoob.com','23453', 'CN']; //增 connection.query(addSql,addSqlParams,function (err, result) { if(err){ console.log('[INSERT ERROR] - ',err.message); return; } console.log('--------------------------INSERT----------------------------'); //console.log('INSERT ID:',result.insertId); console.log('INSERT ID:',result); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();
執行如下命令輸出就結果爲:
$ node test.js
--------------------------INSERT----------------------------
INSERT ID: OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 6,
serverStatus: 2,
warningCount: 0,
message: '',
protocol41: true,
changedRows: 0 }
-----------------------------------------------------------------
執行成功後,查看數據表,便可以看到添加的數據:
咱們也能夠對數據庫的數據進行修改:
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var modSql = 'UPDATE websites SET name = ?,url = ? WHERE Id = ?'; var modSqlParams = ['菜鳥移動站', 'https://m.runoob.com',6]; //改 connection.query(modSql,modSqlParams,function (err, result) { if(err){ console.log('[UPDATE ERROR] - ',err.message); return; } console.log('--------------------------UPDATE----------------------------'); console.log('UPDATE affectedRows',result.affectedRows); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();
執行如下命令輸出就結果爲:
--------------------------UPDATE----------------------------
UPDATE affectedRows 1
-----------------------------------------------------------------
執行成功後,查看數據表,便可以看到更新的數據:
咱們可使用如下代碼來刪除 id 爲 6 的數據:
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var delSql = 'DELETE FROM websites where id=6'; //刪 connection.query(delSql,function (err, result) { if(err){ console.log('[DELETE ERROR] - ',err.message); return; } console.log('--------------------------DELETE----------------------------'); console.log('DELETE affectedRows',result.affectedRows); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();
執行如下命令輸出就結果爲:
--------------------------DELETE----------------------------
DELETE affectedRows 1
-----------------------------------------------------------------
執行成功後,查看數據表,便可以看到 id=6 的數據已被刪除:
參考資料:http://www.runoob.com/nodejs/nodejs-tutorial.html