首先認識一下node.js
Node.js 是一個讓 JavaScript 運行在服務端的開發平臺,它讓 JavaScript 成爲與PHP、Python、Perl、Ruby 等服務端語言平起平坐的腳本語言。發佈於2009年5月,由Ryan Dahl開發,實質是對Chrome V8引擎進行了封裝。
Node.js對一些特殊用例進行優化,提供替代的API,使得V8在非瀏覽器環境下運行得更好。V8引擎執行Javascript的速度非常快,性能非常好。Node.js是一個基於Chrome JavaScript運行時建立的平臺, 用於方便地搭建響應速度快、易於擴展的網絡應用。Node.js 使用事件驅動, 非阻塞I/O 模型而得以輕量和高效,非常適合在分佈式設備上運行數據密集型的實時應用。
以上是百度的定義,node.js就是讓javascript運行在服務端,所以使用的語言就是javascript,它有一個特性,就是上文提到的非阻塞I/O模型,可以簡單的理解爲異步執行,也就是說node.js不會從前到後按順序依次執行代碼指令,而有可能前面的指令還沒執行完畢,後面的代碼就已經開始執行了,這個特性往往會讓新手在初學階段摸不到頭腦,不過沒關係,使用多了,自然就對異步的概念清楚了。
這篇博客就是使用node.js來部署簡單的web後端,實現前後端的通信,接收前端的get、post請求,向前端發送數據、頁面等,node.js的安裝與環境配置,網上很多資源,就不再累述,下面就進入正題。
運行.js程序
首先創建一個.js文件,最簡單的方法就是創建一個文本文件,將後綴改爲.js,也可以用編譯器創建,創建好了,如下:
用編譯器或者記事本等打開,寫入一行命令,如下:
然後打開cmd命令窗口,cd到.js文件所在的目錄,接下來,如果環境配置好了,可以使用node server.js或者省略後綴node server來運行.js程序,如下:
看到已經成功打印出hello了。
架設http服務器
前面是鋪墊,從這裏開始我們就要真正的假設一個服務器了。
我們一般訪問一個網頁,會從地址欄輸入一個網址
https代表Web瀏覽器和網站服務器之間傳遞信息遵從https協議,以前都是用http協議傳輸,但現在已經逐漸都在使用https了,因爲https比http更加安全。
www.baidu.com就是百度的域名,沒有註冊域名之前,我們可以使用"ip地址:端口號"的形式來訪問,比如https://localhost:8888,localhost即訪問本機,也可以是其他的ip地址。
http模塊
架設http服務器,http模塊是必不可少的。
我們分3步走:
這樣我們就建好了一個最簡單的http服務器,我們運行server.js程序,然後在瀏覽器地址欄裏輸入http://localhost:8888,訪問,
可以看到後端輸出new message說明後端接收到了前端的請求。我們後端監聽的是8888端口,並且前端訪問的也是8888端口,所以當前端向後端發送請求時,後端監聽到8888端口有請求,於是就會調用http服務,打印出new messge,這就是程序執行的過程。
http服務裏面接收兩個參數req和res,req是request的縮寫,res是response的縮寫,一個代表請求,一個代表迴應,前端向後端發送的數據一般在req裏,而後端向前端返回數據時,一般用res向前端返回,具體用法,往下看。
架設路由
路由這個概念是網絡中很重要的一個概念,但具體含義我也解釋不太清楚,在這裏可以簡單理解爲後端不同的分支對應前端不同的請求吧,看一下事例,就能夠非常清晰的解釋了。
req有許多的屬性,感興趣的可以打印一下req,可以看到有非常多的屬性,我們這裏用到一個比較重要的屬性url,url是統一資源定位符,對可以從互聯網上得到的資源的位置和訪問方法的一種簡潔的表示,是互聯網上標準資源的地址。
剛剛我們請求的是http://localhost:8888,接下來我們請求比如http://localhost:8888/index
然後打印req.url,輸出如下:
可以看到對於不同的請求地址,req.url也是不同的,這意味着我們可以架設不同的分支,來處理不同的請求。事例如下:
再試試請求不同的地址:
很明顯不同的請求,後端進入了不同的分支,並向前端返回不同的消息,這就是架設路由。
我們這裏用到了一個新函數,res.write(),顧名思義,就是寫入數據,而我們的對象是res,也就是前端頁面,所以我們向前端頁面傳送了一串字符數據,注意這裏write()後面一定要跟上end()來結束傳輸,不然前端是收不到數據的,會一直處於等待後端響應的狀態。
解析GET請求,獲取參數
在實際使用中,前端常常會向後端傳送一些數據,我們需要知道,只要是在地址欄裏輸入地址來訪問頁面,都是發送一個GET請求,此時GET請求的參數可以在url中獲取:
地址?後面所接的就是GET請求傳送的數據,下面我們講如何從後端獲取這裏的數據。
爲了解析url,我們需要引入url模塊。
請求圖中url,解析後,返回一個urlobject對象,它的屬性如下:
可以看到參數在query屬性裏,路由則在pathname裏。但是query是以字符串的方式儲存的參數的,使用時不方便,我們可以在url.parse()裏添加第二個參數true,這樣解析時就會自動把參數轉換爲對象了。
fs模塊
fs是file system的簡稱,用於讀寫文件。
下面介紹幾個重要的函數
var fs = require('fs')
fs.exist(path, function (bol) {//功能是判斷一個文件是否存在
//第一個參數是需要判斷的文件的路徑,爲一個字符串
//第二個參數是一個回調函數,回調函數的參數爲一個布爾類型,如果爲true則文件存在,否則不存在
})
fs.realpath(path, function (err, realpath) {//功能是把相對路徑轉換爲絕對路徑
//第一個參數是相對路徑,
//回調函數的第一個參數是錯誤信息,若成功,則第二個參數保存轉換成功的絕對路徑
})
fs.rename(path, new_name, function (err) {//功能是重命名一個文件
//第一個參數是需要修改的源文件路徑
//第二個參數是重新命名的名字
//回調函數的參數是若修改失敗的錯誤信息
})
fs.readFile(path, coded_format, function (err,data) {//功能是讀一個文件
//第一個參數路徑是讀取的文件路徑
//第二個參數是讀取時的編碼格式,如'utf-8'
//回調函數的參數,err是若錯誤的錯誤信息,data是若成功,讀取的數據
})
fs.writeFile(path, content,operation, function (err) {
//第一個參數是寫入的文件路徑
//第二個參數是寫入的內容
//第三個參數是寫入控制操作,如覆蓋寫入、追加寫入、指定編碼格式等
//回調函數的參數err指示錯誤信息
})
對於較大的文件,應使用管道流的方式讀寫,管道流與普通的讀寫方式的區別是,普通的讀寫方式,是整讀整寫,一次性操作;而管道流是分塊讀寫,每次傳輸64k大小的數據。管道流的優勢是,如果傳輸過程中出現錯誤,那麼之前已經傳輸的內容不會丟失,下次只要接着傳輸就可以了,而普通讀寫,如果出現錯誤,則這次讀寫的失敗了。不過因爲管道流的分塊讀寫方式,我們需要把收到的數據拼接起來,才能獲得完整數據。
var fs = require('fs')
var stream = fs.createReadStream(path)//創建一個讀取流,參數是讀取的文件的路徑
var data = null
stream.on('data', function (chunk) {
//爲讀取流綁定讀取事件,每一次讀取都會觸發,chunk的意思是片、塊,就是一次讀取的數據塊
data += chunk//拼接數據
})
console.log(data)//完整數據
stream.on('end', function () {
//讀取結束時觸發
})
//數據是buffer類型時,可以用toString()方法轉換成字符串
var fs = require('fs')
var stream = fs.createWriteStream(path)//創建一個寫入流,參數是寫入的文件的路徑
stream.write(content)//通過管道流的方式寫入,參數是寫入內容
readStream.pipe(writeStream)//也可以用這種方式把讀取流的數據寫入寫入流,這種方式與上面一種的區別是,它會等待每次數據寫入完成後,纔會進行下一次讀取,內存利用率高。而上一種方法,讀取速度快於寫入速度,則等待寫入的數據會滯留在內存中,佔用內存。
解析POST請求
post和get請求是前後端交互最重要的請求,post與get請求的區別是,get請求的參數是拼接在url後面的,而post請求的參數卻是在頭部,post請求是通過發送數據包的方式把數據在前端與後端之間傳輸,下面我們就介紹如何把參數從post請求解析出來。
首先準備一個html頁面,做演示用:
請求http://localhost:8888/index.html,後端會向前端發送這個頁面。後端代碼:
在賬號欄和密碼欄填入123,點擊提交,後端顯示如下:
然後把method改爲POST,再請求,後端顯示如下:
參數不能通過與get請求同樣的方法獲取,說明參數放在別的地方。
將後端代碼修改如下,用管道流的方式把數據從req中提取出來:
var http = require('http')
var url = require('url')
var fs = require('fs')
var server = http.createServer(function (req, res) {
var urlObj = url.parse(req.url,true);
if(urlObj.pathname=="/index.html"){
var rs = fs.createReadStream("./index.html");
var index = null;
rs.on('data',function(chunk){
index+=chunk
})
rs.pipe(res)
}
else if(urlObj.pathname=="/login"){
var data = '';
req.on('data',function(chunk){
data+=chunk
});
req.on('end',function(){
console.log(data)
})
}
})
server.listen(8888, function () {
console.log('start server')
})
後端輸出如下:
我們已經成功獲取了POST請求的數據,但是它不是我們想要的格式,我們可以引用一個第三方庫'querystring' :
var qs = require('querystring')
...
req.on('end',function(){
var queryObj = qs.parse(data)
console.log(queryObj)
})
...
後臺輸出如下:
當我們使用express模塊時,還可以使用body-parser中間件來解析數據,對於body-parser的使用,這篇博客寫的很詳細
https://blog.csdn.net/yanyang1116/article/details/54847560