Node.js 是一個基於 Chrome V8 引擎的 JavaScript 運行環境。 Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。html
簡單的理解,Node.js 就是運行在服務端的 JavaScript。前端
咱們能夠經過 Node.js 實現服務端的開發,對於前端程序員來講,不管是從上手難易程度仍是從性能角度,node 都是很是理想的選擇。node
安裝 node 咱們能夠在下面的網址選擇適合本身的版本下載。程序員
Node 網址:npm
https://nodejs.org/en/
下載完成以後安裝便可。數組
安裝過程當中只須要不斷的點擊下一步便可。緩存
安裝完成後,能夠win+r
鍵輸入 cmd,在命令提示窗口中輸入node -v
出現版本號即表示安裝成功。服務器
NPM 是隨同 node 一塊兒安裝的包管理工具,經過 NPM 咱們能夠很是方便的安裝一些經常使用的包,以及解決 Node 部署等一些問題。架構
同時,咱們也能夠經過 NPM 將本身的包上傳到 NPM 供別人使用。app
由於 NPM 是隨着 Node 一切安裝的工具,因此只要 Node 安裝成功,那麼咱們就能夠直接使用 npm。
經過下面的命令能夠查看 NPM 的版本。
npm -v
由於 NPM 的服務器架設在國外,因此當咱們安裝一些包的時候不免會產生速度上的問題致使下載失敗,因此不少時候咱們須要切換下載的服務器,咱們將之稱爲源
。而 nrm 就是用來幫我咱們切換下載源的一個工具。
首先先來經過 npm 安裝 nrm。
npm install -g nrm install:安裝 -g 全局安裝 若是不加-g表示只安裝在當前的目錄 nrm 包名
經常使用源
通常在國內從事 node 開發,常用的源以下:
當咱們安裝完 nrm 以後,能夠經過nrm ls
來查看可選的源。
* npm ---- https://registry.npmjs.org/ cnpm --- http://r.cnpmjs.org/ taobao - https://registry.npm.taobao.org/ nj ----- https://registry.nodejitsu.com/ npmMirror https://skimdb.npmjs.com/registry/ edunpm - http://registry.enpmjs.org/
帶有* 的源地址表示是當前正在使用的源
切換源
能夠經過下面的這條命令切換源:
nrm use 源名
例如,想要使用淘寶的源,能夠採用以下的命令:
nrm use taobao
測試速度
咱們能夠經過nrm test
測試相應源的響應時間。
例如,想要測試官方源的響應時間,能夠採用以下的寫法:
nrm test npm
咱們也能夠測試全部源的速度。
nrm test
咱們在開發 node 項目的時候,每一次代碼的更改,都須要從新啓動一次 node 服務器,相對來講對咱們的開發並非很方便,因此咱們能夠選擇使用nodemon
工具,能夠很好的幫助咱們調試代碼。
安裝方式:
npm install -g nodemon
啓動應用
當咱們須要啓動應用的時候,以前是經過:
node appName
若是要使用 nodemon 的話,則能夠改成以下:
nodemon appName
查看幫助文檔
若是想要查看內置的幫助文檔,能夠經過以下:
nodemon -h 或者 nodemon --help
設置端口
若是沒有在代碼中設置端口,那麼能夠經過下面的命令在運行的時候設置端口:
nodemon ./server.js localhost 8080
開啓 debug 模式
若是想要開啓 debug 模式,能夠經過以下的命令:
nodemon --debug ./server.js 80
在 node.js 中,應用由模塊組成,採用 CommonJS 模塊規範。
簡單點說,每個文件就是一個模塊,擁有屬於本身的做用域。在每個模塊當中定義的變量、函數、類都是私有的,也就是說對其餘的文件不可見。
例如,在 a.js 中,存在一個變量 x 的內容是hello,world
。此時,變量 x 至關於在 a.js 中的私有變量。只可以在 a 中使用。
可是在 b.js 中,若是想要使用 a.js 中的變量 x,那麼能夠採用以下的寫法:
let x = "hello,world"; module.exports.x = x; // 至關於將這個變量輸出
在 b.js 中使用以下:
let info = require("./a.js"); console.log(info.x); //hello,world
CommonJS 模塊的特色以下:
* 全部代碼都運行在模塊做用域,不會污染全局做用域。 * 模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果。要想讓模塊再次運行,必須清除緩存。 * 模塊加載的順序,按照其在代碼中出現的順序。
經過http
模塊,咱們能夠快速的建立一個服務器,用於開發和測試。
const http = require("http"); // 建立一個服務 let server = http.createServer((req,res)=>{ res.write("hello,Node!"); res.end(); }); // 監聽端口 server.listen(8080);
在上面的代碼中,咱們首先經過require
引入了http模塊。
其次經過createServer
方法建立了一個服務,而且經過listen
方法監聽了8080
端口。
在上面的代碼中,res.write()
方法和res.end()
方法是兩個很是重要的方法,write
表示向客戶端輸入內容,而end
方法則告訴客戶端,響應結束。
在createServer
方法中,須要一個回調函數,這個回調函數中須要設置兩個形參,一個是req
,表示request
,另一個是res
,表示response
,兩個形參分別對應着請求和響應。
咱們能夠經過req
獲取更多的關於請求的內容。
例如能夠經過req.url
獲取用戶請求的地址以及get請求傳遞的參數。
const http = require("http"); // 建立一個服務 let server = http.createServer((req,res)=>{ res.write(req.url); res.end(); }); // 監聽端口 server.listen(8080);
例如上面的代碼,當用戶輸入的地址爲localhost:8080/index.html
的時候,在網頁當中就會輸出/index.html
。
咱們若是想要經過url獲取用戶的更多的信息,可使用url
模塊。
const url =require("url");
在url
對象當中,咱們可使用parse()
方法來解析url信息。
const http = require("http"); const url = require("url"); // 建立一個服務 let server = http.createServer((req,res)=>{ console.log(url.parse(req.url)); // 獲取url路徑信息 res.write(req.url); res.end(); }); // 監聽端口 server.listen(8080);
上面的代碼經過url對象的parse方法打印出了url的信息以下:
Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: null, query: null, pathname: '/index.html', path: '/index.html', href: '/index.html' }
若是咱們在其中還傳入了一些其餘的參數,那麼相同的代碼打印結果可能與下面的內容相似:
Url { protocol: null, slashes: null, auth: null, host: null, port: null, hostname: null, hash: null, search: '?username=zhangsan', query: 'username=zhangsan', pathname: '/index.html', path: '/index.html?username=zhangsan', href: '/index.html?username=zhangsan' }
若是咱們想要得到其中的參數,能夠直接採用以下的代碼:
let req_info = url.parse(req.url); console.log(req_info.query);// 輸出信息相似於 username=zhangsan&age=30
若是想要對數據進行必定的處理,能夠採起相似以下的代碼:
const http=require('http'); const querystring=require('querystring'); let server=http.createServer(function (req, res){ let [url, query]=req.url.split('?'); let get=querystring.parse(query); console.log(url, get); res.end(); }); server.listen(8080);
在上面的代碼中,咱們爲了更加細緻的處理url,引入了querystring
模塊。
const querystring=require('querystring');
首先咱們經過split
方法將地址和參數以?
爲分界切割開。而且將結果解構賦值給url和query兩個變量。
let [url, query]=req.url.split('?');
若是咱們須要進一步解析數據,咱們能夠經過querystring
裏面的parse()
方法,直接解析query
。
let get=querystring.parse(query);
若是客戶端發送的是post請求,那麼處理方式能夠以下:
// server.js const http = require("http"); const querystring = require("querystring"); let server = http.createServer((req,res)=>{ let arr = []; req.on('data',buffer=>{ arr.push(buffer); // 將buffer數據存入到數組當中 }) req.on("end",()=>{ let buffer = Buffer.concat(arr); // 緩衝區合併 let post=querystring.parse(buffer); res.write(buffer); //將內容輸出網頁當中去 res.end(); }) }) server.listen(8080)
在上面的代碼中,咱們經過req
中的on
方法來處理用戶經過post方法傳遞過來的數據,而且隨着數據的傳遞將數據以buffer的形式存入到數組當中。
let arr = []; req.on('data',buffer=>{ arr.push(buffer); // 將buffer數據存入到數組當中 })
緊接着,當數據傳遞結束後,經過Buffer.concat()
方法來將緩衝區的buffer數據合併。
req.on("end",()=>{ let buffer = Buffer.concat(arr); // 緩衝區合併 let post=querystring.parse(buffer); res.write(buffer); //將內容輸出網頁當中去 res.end(); })
須要注意的是,buffer
數據是一組二進制的數據的數據,雖然咱們不認識,可是電腦認識,因此咱們無需處理,直接輸入到網頁中便可。若是想要看其內容,能夠在其後面使用toString
方法。
咱們能夠經過fs
模塊來實現文件的讀取工做。
const fs = require("fs");
在fs
模塊當中有四個經常使用的方法,以下:
fs.writeFile() 異步寫入文件 fs.writeFileSync() 同步寫入文件 fs.readFile() 異步讀取文件 fs.readFileSync() 同步讀取文件
上面的四個方法,咱們較爲經常使用的是兩個異步的方法,由於不管是從速度仍是從性能的角度考慮,異步都要好於同步。
其中,兩個異步方法須要的參數以下:
fs.readFile(path,callback) ;// 路徑和回調函數 fs.writeFile(path,data,callback);// 路徑 數據 回調函數
例如,咱們想要讀取一個文件,能夠以下:
const fs = require("fs"); fs.readFile('./aa.txt',(err,data)=>{ if(err){ console.log('失敗,'+err); }else { console.log(data.toString()); // hello,world } })
上面的代碼中,經過在readFile
中傳入第一個參數須要讀取的文件路徑
,第二個參數callback
。
fs.readFile('./aa.txt',(err,data)=>{}
其中,若是讀取文件失敗,那麼就提示錯誤信息。若是想要查看讀取的內容,能夠在獲得的數據後面使用toString()
方法。
if(err){ console.log('失敗,'+err); }else { console.log(data.toString()); // hello,world }
下面是經過writeFile()
方法寫入內容:
fs.writeFile("bb.txt","hi,this file is bb.txt",err=>{ if(err){ console.log("失敗:" + err); }else { console.log("成功"); } })
上面的代碼中,在調用writeFile()
時,傳入的第一個參數是寫入的文件路徑和文件名
,第二個參數是要寫入的數據,第三個參數則是一個回調函數,在回調函數中存在一個形參err
,當寫入出錯時就會傳入參數,經過err
這個形參就能夠獲取錯誤信息。
當用戶在客戶端請求一個文件的時候,咱們能夠經過服務端進行判斷,而且經過readFile()
方法讀取指定位置的文件。
const http = require("http"); const fs = require("fs"); let server = http.createServer((req,res)=>{ if (req.url === "/a.png"){ fs.readFile("./a.png",(err,data)=>{ if(err){ res.write("請求失敗:" + err); }else { res.write(data); } res.end(); }) } }); server.listen(8080);
在上面的代碼中,咱們首先建立了服務器。
http.createServer((req,res)=>{})
咱們經過req.url
來判斷客戶端請求的路徑,若是用戶請求的是a.png
,那麼就去讀取本地的文件。
if(req.url === "/a.png"){ fs.readFile("./a.png",(err,data)=>{ }) }
在回調函數中,若是請求出錯,就返回err
錯誤信息,若是沒有請求出錯,那麼就直接輸出數據信息。
if(err){ res.write("請求失敗:" + err); }else { res.write(data); } res.end();
咱們若是想要判斷客戶端請求的方法,那麼能夠經過method
來進行判斷。
let server = http.createServer((req,res)=>{ if(req.method === "GET"){ console.log("請求方法爲get.."); }else if(req.method === "POST"){ console.log("請求方法爲POST..."); } });
上面代碼中,若是客戶端發送的請求爲get請求,那麼就是輸出請求方法爲get
,若是發送的請求爲post,那麼就是輸出請求方法爲post
。
下面咱們來簡單的作一個路由配置。
須要注意的是,實際的項目開發當中,路由每每都是經過框架構建而成。
// 路由配置 const http = require('http'); const url = require('url'); const querystring = require('querystring'); const fs = require('fs'); let users={}; // 先來建立一個簡單的服務器 let server = http.createServer((req, res) => { // 建立幾個變量用來存儲位置信息 let path = '', get = {}, post = {}; if (req.method === "GET") { let { pathname, query } = url.parse(req.url, true); path = pathname; get = query; complete(); } else if (req.method == 'POST') { path = req.url; let arr = []; req.on('data', buffer => { arr.push(buffer); }); req.on('end', () => { let buffer = Buffer.concat(arr); post = querystring.parse(buffer.toString()); complete(); }); } function complete() { if (path == '/reg') { let { username, password } = get; if (users[username]) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '此用戶名已存在' })); res.end(); } else { users[username] = password; res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 0, msg: '' })); res.end(); } } else if (path == '/login') { let { username, password } = get; if (!users[username]) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '找不到此用戶' })); res.end(); } else if (users[username] != password) { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 1, msg: '密碼不對' })); res.end(); } else { res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'}); res.write(JSON.stringify({ error: 0, msg: '' })); res.end(); } } else { fs.readFile(`www${path}`, (err, buffer) => { if (err) { res.writeHeader(404); res.write('Not Found'); res.end(); } else { res.write(buffer); res.end(); } }); } } }); server.listen(8080);