初識Node之Node中的js
#一、Nod.js基本概念 ##1.為什麼學Node `-`**企業需求:**具有服務端開發需求 `-`**目的:**開啟服務端黑匣子 `-`**網站開發能力:**服務端,前端,運維部署 ##2.Node是什麼? `-`Node.js不是語言,不是庫,也不是框架 `-`是JS執行時環境(是一個平臺),可以解析和執行JS程式碼 ##3. Node.js 中的 JavaScript + 沒有 BOM、DOM + EcmaScript 基本的 JavaScript 語言部分 + 在 Node 中為 JavaScript 提供了一些伺服器級別的 API * 檔案操作的能力 * http 服務的能力 * 網路服務構建的能力 + EcmaScript * 變數 * 方法 * 資料型別 * 內建物件 * Array * Object * Date * Math #二、基本Node操作 ##1.使用Node執行js指令碼檔案 **注意:**node檔名**不要用node.js命名**,**不要使用中文** ###例1 ``` var foo = 'hello nodejs' console.log(foo) ``` 在終端或者cmd裡中node + 檔名便可執行檔案 ![結果](https://upload-images.jianshu.io/upload_images/2549157-f1888137b62bd243.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
(我這個檔案的名字叫做Hello_wrold.js) 可以看出,node和js基本語法一樣 <hr> ###例2 ``` console.log(window) console.log(document) ``` 我們在node中執行js的一些操作,結果如下: ![結果](https://upload-images.jianshu.io/upload_images/2549157-4a1c2857b634aca3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 沒有任何輸出,但是我們在html中開啟瀏覽器介面,引用這個js檔案在控制檯可以看見 ![結果](https://upload-images.jianshu.io/upload_images/2549157-665e7f6f2575644c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **注意:**Node和瀏覽器中的 JavaScript 不一樣 ##2.Node的讀檔案基本操作 **注意:** `1.`瀏覽器中的 JavaScript 是沒有檔案操作的能力的,但是 Node 中的 JavaScript 具有檔案操作的能力 `2.`在 Node 中如果想要進行檔案操作,就必須引入 fs 這個核心模組; 在 fs 這個核心模組中,就提供了所有的檔案操作相關的 API `3.`fs 是 file-system 的簡寫,就是檔案系統的意思;例如:fs.readFile 就是用來讀取檔案的 ####a.使用 require 方法載入 fs 核心模組 >var fs = require('fs') ####b.讀取檔案 **注意:** `1.`第一個引數就是要讀取的檔案路徑 `2.`第二個引數是一個回撥函式 `3.`回撥函式又有兩個引數:error和data;如果讀取路徑成功,data返回資料,error返回null;反之,如果讀取路徑失敗,data返回null,error返回錯誤物件
``` fs.readFile('./data/hello.txt', function (error, data) { console.log(data) }) ``` (我建立了一個名為data的資料夾,裡面儲存了一個名為hello.txt的檔案,內容為:hello node) 結果如下:![image.png](https://upload-images.jianshu.io/upload_images/2549157-cfe41a719ece5756.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **注意:** ><Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>
檔案中儲存的其實都是二進位制資料 0 1; 這裡為什麼看到的不是 0 和 1 呢?原因是二進位制轉為 16 進位制了;但是無論是二進位制01還是16進位制,人類都不認識;所以我們可以通過 toString 方法把其轉為我們能認識的字元 ``` var fs = require('fs') fs.readFile('./data/hello.txt', function (error, data) { //console.log(data) console.log(data.toString()) //hello node }) ``` <hr> **在這裡存在一個小問題:** 如果我們將路徑寫錯了,看看上面寫的程式碼會出現什麼問題。 ``` var fs = require('fs') fs.readFile('./data/a.txt', function (error, data) { console.log(data) }) ``` ![結果](https://upload-images.jianshu.io/upload_images/2549157-02a9ba99e0641f59.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 因為data裡面是null,所以結果為undefined 在這裡就可以通過判斷 error 來確認是否有錯誤發生 ``` var fs = require('fs') fs.readFile('./data/a.txt', function (error, data) { //console.log(data) //console.log(data.toString()) if (error) { console.log('讀取檔案失敗了') } else { console.log(data.toString()) } }) ``` 如果讀取失敗,結果如下圖所示: ![讀取失敗結果](https://upload-images.jianshu.io/upload_images/2549157-e318c832fb2c9f8b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ##3.Node的寫檔案基本操作 ####a.寫檔案的第一步也是使用require載入fs核心模組 >var fs = require('fs')
####b.寫入檔案 ``` fs.writeFile('./data/你好.md', '大家好,給大家介紹一下,我是Node.js', function (error) { console.log('檔案寫入成功') }) ``` 結果會在控制檯輸出:檔案寫入成功 同時在data檔案下新建你好.md檔案,並把內容寫入 ![寫檔案操作](https://upload-images.jianshu.io/upload_images/2549157-2ee81beee9b74588.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) **注意:**writeFile有三個引數 `1.`第一個引數:檔案路徑 `2.`第二個引數:檔案內容 `3.`第三個引數:回撥函式。回撥函式在這裡只有一個引數error;若檔案寫入成功,error 是 null;若檔案寫入失敗,error 就是錯誤物件 <hr> **注意:** **在這裡存在一個小問題:** 如果我們將路徑寫錯了,看看上面寫的程式碼會出現什麼問題。 ``` fs.writeFile('./d/你好.md', '大家好,給大家介紹一下,我是Node.js', function (error) { console.log('檔案寫入成功') }) ``` 我把data資料夾改成了d資料夾 結果如下:![寫入檔案錯誤](https://upload-images.jianshu.io/upload_images/2549157-c73e1485f328373c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 只是在控制檯輸出語句,但是在data資料夾裡沒有新建檔案,也沒有新建d資料夾。 <hr> 因此,我們可以在這裡加上 if 語句進行判斷 ``` fs.writeFile('./data/你好.md', '大家好,給大家介紹一下,我是Node.js', function (error) { if (error) { console.log('寫入失敗') } else { console.log('寫入成功了') } })
``` #三、Node之http服務 ##1.簡單的http服務 我們可以使用 Node 非常輕鬆的構建一個 Web 伺服器;在 Node 中專門提供了一個核心模組:http;http 這個模組的職責就是幫你建立編寫伺服器的 ####a.載入 http 核心模組 >var http = require('http') ####b.使用 http.createServer() 方法建立一個 Web 伺服器;返回一個 Server 例項 >var server = http.createServer() ####c.註冊 request 請求事件 當客戶端請求過來,就會自動觸發伺服器的 request 請求事件,然後執行第二個引數:回撥處理函式 ``` server.on('request', function () { console.log('收到客戶端的請求了') }) ``` ####d.繫結埠號,啟動伺服器 ``` server.listen(3000, function () { console.log('伺服器啟動成功了,可以通過 http://127.0.0.1:3000/ 來進行訪問') }) ``` 執行該JS檔案後,就可以開啟瀏覽器 **埠號範圍:**0~65536 ##2.傳送響應 **request 請求事件處理函式,需要接收兩個引數:** + Request 請求物件 * 請求物件可以用來獲取客戶端的一些請求資訊,例如請求路徑 + Response 響應物件 * 響應物件可以用來給客戶端傳送響應訊息 + response 物件有一個方法:write 可以用來給客戶端傳送響應資料 * write 可以使用多次,但是最後一定要使用 end 來結束響應,否則客戶端會一直等待 ``` var http = require('http') var server = http.createServer()
server.on('request', function (request, response) { console.log('收到客戶端的請求了,請求路徑是:' + request.url)
response.write('hello') response.write(' nodejs') response.end() })
server.listen(3000, function () { console.log('伺服器啟動成功了,可以通過 http://127.0.0.1:3000/ 來進行訪問') })
``` 結果在瀏覽器輸出: ![瀏覽器輸出](https://upload-images.jianshu.io/upload_images/2549157-6ba8b297851b0ddd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) <hr> ##3.練習:根據不同的請求路徑返回不同資料 **注意:** 上面使用的 res.write方式比較麻煩,推薦使用更簡單的方式,直接 end 的同時傳送響應資料 ``` // res.write('hello') // res.write(' world') // res.end() res.end('hello nodejs') ``` ####練習分析:根據不同的請求路徑傳送不同的響應結果 `-` **1. 獲取請求路徑** `+`req.url 獲取到的是埠號之後的那一部分路徑 ·`+` url:同一資源定位符,一個url其實是要定一個資源 `+`也就是說所有的 url 都是以 / 開頭的 `-` **2. 判斷路徑處理響應** `+`響應內容只能是二進位制資料或者字串、數字、物件、陣列、布林值 ``` var http = require('http') var server = http.createServer() server.on('request', function (req, res) { console.log('收到請求了,請求路徑是:' + req.url) console.log('請求我的客戶端的地址是:', req.socket.remoteAddress, req.socket.remotePort) var url = req.url
if (url === '/') { res.end('index page') } else if (url === '/login') { res.end('login page') } else { res.end('404 Not Found.') } }) server.listen(3000, function () { console.log('伺服器啟動成功,可以訪問了。。。') })
``` #4.埠號 **ip 地址定位計算機** **埠號定位具體的應用程式** **所有需要聯網通訊的應用程式都會佔用一個埠號** 在cmd中輸入 >ipconfig
可以檢視本機的埠號 在同一區域網的計算機可以訪問自己的計算機 **req.socket.remoteAddress**:當前請求我的計算機客戶端的地址(ip地址和埠號) **req.socket.remotePort**:當前請求我的計算機客戶端的埠號 <hr> 根據下列程式碼可以看見訪問自己計算機的ip地址和埠號 ``` var http = require('http')
var server = http.createServer()
server.on('request', function (req, res) { console.log('收到請求了,請求路徑是:' + req.url) console.log('請求我的客戶端的地址是:', req.socket.remoteAddress, req.socket.remotePort)
res.end('hello nodejs') })
server.listen(5000, function () { console.log('伺服器啟動成功,可以訪問了。。。') }) ``` ##5.Content-Type * 伺服器最好把每次響應的資料是什麼內容型別都告訴客戶端,而且要正確的告訴 * 不同的資源對應的 Content-Type 是不一樣,具體參照:http://tool.oschina.net/commons * 對於文字型別的資料,最好都加上編碼,目的是為了防止中文解析亂碼問題 <hr> ####a.在瀏覽器中輸出漢字 在之前的學習中,如果我們在res.end中寫入中文的話,開啟瀏覽器會出現亂碼的情況; 其實在服務端預設傳送的資料,其實是 utf8 編碼的內容;但是瀏覽器不知道你是 utf8 編碼的內容;瀏覽器在不知道伺服器響應內容的編碼的情況下會按照當前作業系統的預設編碼去解析;中文作業系統預設是 gbk **解決辦法:** 就是正確的告訴瀏覽器我給你傳送的內容是什麼編碼的;在 http 協議中,Content-Type 就是用來告知對方我給你傳送的資料內容是什麼型別 >res.setHeader('Content-Type', 'text/plain; charset=utf-8')
再輸出res.end語句結果就正確了 **text/plain 就是普通文字** ####b.在瀏覽器中輸出html標籤 如果你傳送的是 html 格式的字串,則也要告訴瀏覽器我給你傳送是 text/html 格式的內容 ``` res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end('<p>hello html <a href="">點我</a></p>') ``` 結果會在瀏覽器中渲染成html標籤 <hr> 利用檔案的方法,將html檔案渲染成頁面 ``` fs.readFile('./resource/index.html', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('檔案讀取失敗,請稍後重試!') } else { res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end(data) } }) ``` ####c.在瀏覽器中輸出圖片 `-`傳送的並不是檔案,本質上來講傳送是檔案的內容 `-`當瀏覽器收到伺服器響應內容之後,就會根據你的 Content-Type 進行對應的解析處理;圖片不需要指定編碼;一般只為字元資料才指定編碼 ``` fs.readFile('./resource/ab2.jpg', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('檔案讀取失敗,請稍後重試!') } else { res.setHeader('Content-Type', 'image/jpeg') res.end(data) } }) ``` #四、Node中的js-模組系統 在 Node 中沒有全域性作用域的概念;在 Node 中,只能通過 require 方法來載入執行多個 JavaScript 指令碼檔案 ##1.Node.js中的核心模組 * 核心模組是由 Node 提供的一個個的具名的模組,它們都有自己特殊的名稱標識,例如 - fs 檔案操作模組 - http 網路服務構建模組 - os 作業系統資訊模組 - path 路徑處理模組 * 所有核心模組在使用的時候都必須手動的先使用 `require` 方法來載入,然後才可以使用,例如: - `var fs = require('fs')` ``` // 用來獲取機器資訊的 var os = require('os')
// 用來操作路徑的 var path = require('path')
// 獲取當前機器的 CPU 資訊 console.log(os.cpus())
// memory 記憶體 console.log(os.totalmem())
// 獲取一個路徑中的副檔名部分 // extname extension name console.log(path.extname('c:/a/b/c/d/hello.txt'))
``` ##2.Node.js中的模組系統 * 在 Node 中沒有全域性作用域的概念 * 在 Node 中,只能通過 require 方法來載入執行多個 JavaScript 指令碼檔案 * require 載入只能是執行其中的程式碼,檔案與檔案之間由於是模組作用域,所以不會有汙染的問題 - 模組完全是封閉的 - 外部無法訪問內部 - 內部也無法訪問外部 * 模組作用域固然帶來了一些好處,可以載入執行多個檔案,可以完全避免變數命名衝突汙染的問題 * 但是某些情況下,模組與模組是需要進行通訊的 * 在每個模組中,都提供了一個物件:`exports` * 該物件預設是一個空物件 * 你要做的就是把需要被外部訪問使用的成員手動的掛載到 `exports` 介面物件中 * 然後誰來 `require` 這個模組,誰就可以得到模組內部的 `exports` 介面物件 * 還有其它的一些規則,具體後面講,以及如何在專案中去使用這種程式設計方式,會通過後面的案例來處理