Node基本
- node的最大特性莫過于基于事件驅(qū)動的非阻塞I/O模型钧舌。
- node通過事件驅(qū)動的方式處理請求凰狞,無須為每一個請求創(chuàng)建額外的對應(yīng)線程叨咖,可以省掉創(chuàng)建線程和銷毀線程的開銷,同時操作系統(tǒng)在調(diào)度任務(wù)時因為線程較少惋戏,上下文切換的代價很低邀杏。這使得服務(wù)器能夠有條不紊地處理請求贫奠,即使在大量連接的情況下,也不受線程上下文切換開銷的影響望蜡,這是Node高性能的一個原因唤崭。Apache會為每個請求啟動一個線程,每個線程會占用一定內(nèi)存脖律,并發(fā)量較大時會緩慢谢肾。Nginx也使用和node一樣的事件驅(qū)動方式處理請求。
- node對引入過的模塊都會進(jìn)行緩存小泉,以減少二次引入時的開銷芦疏,node緩存的是編譯和執(zhí)行后的對象冕杠。不論是核心模塊還是文件模塊,require( )方法對相同模塊的二次加載都一律采用緩存優(yōu)先的方式眯分,這是第一優(yōu)先級的。不同之處在于核心模塊的緩存檢查先于文件模塊的緩存檢查柒桑。
- 事件輪詢:從本質(zhì)上來說弊决,node會先注冊事件,隨后不停地詢問內(nèi)核這些時間是否已經(jīng)分發(fā)魁淳。當(dāng)事件分發(fā)時飘诗,對應(yīng)的回調(diào)函數(shù)就會被觸發(fā),然后繼續(xù)執(zhí)行下去界逛。如果沒有事件觸發(fā)昆稿,則繼續(xù)執(zhí)行其他代碼,直到有新事件時息拜,再去執(zhí)行對應(yīng)的回調(diào)函數(shù)溉潭。
- 在程序中定義配置項如app.set(“photo”,__dirname+’/public/photos’)后就可以在各種環(huán)境下任意改變此目錄。
- 當(dāng)node接收到從瀏覽器發(fā)來的http請求時少欺,底層的TCP連接會分配一個文件描述符喳瓣。隨后,如果客戶端向服務(wù)器發(fā)送數(shù)據(jù)赞别,node就會收到該文件描述符上的通知畏陕,然后觸發(fā)JavaScript的回調(diào)函數(shù)。
- 對于阻塞式I/O線程在執(zhí)行中遇到磁盤讀寫或者數(shù)據(jù)庫通訊仿滔,網(wǎng)絡(luò)通訊這種耗時比較多的時候惠毁,操作系統(tǒng)將會剝奪此線程的CPU資源,并暫停此線程崎页,轉(zhuǎn)而去執(zhí)行別的線程鞠绰。異步式I/O則針對所有操作采取不阻塞的方法,當(dāng)線程遇到I/O操作時將操作發(fā)送給操作系統(tǒng)飒焦,然后接著執(zhí)行下一個操作洞豁,當(dāng)操作系統(tǒng)執(zhí)行完I/O操作之后,將以事件的方式通知執(zhí)行I/O的線程荒给,線程會在特定的時候執(zhí)行這個事件丈挟。這一切的前提就是系統(tǒng)需要一個時間循環(huán),以不斷地去查詢有沒有未處理的事件志电,然后交給預(yù)處理曙咽。對比與阻塞I/O,異步模型極大提高了web服務(wù)器的并發(fā)性挑辆。
- buffer是一個表示固定內(nèi)存分配的全局對象(即放到緩沖區(qū)的字節(jié)數(shù)需要提前確定)
- node的HTTP服務(wù)器是構(gòu)建于node TCP服務(wù)器之上的例朱,即node中的HTTP.server繼承自net.server(net為TCP模塊)孝情。TCP的首要特性是它面向連接。
- Node中的管道可以讓數(shù)據(jù)流動到指定目的地(即WriteableStream)讀取一個文件并寫入到另一個文件中洒嗤,利用pipe()作為連接箫荡,ReadableStream.pipe(WriteableStream).HTTP請求中在客戶端request就是一個WriteableStream,response為Readablestream渔隶,而在服務(wù)器端則相反羔挡。
- node與操作系統(tǒng)交互的工具
- 全局的process對象————包含當(dāng)前進(jìn)程的相關(guān)信息,如傳參和當(dāng)前設(shè)定的環(huán)境變量
- fs模塊————包含底層的ReadStream和WriteStream類间唉。
- child_process模塊————繁衍子進(jìn)程的底層和高層接口绞灼,以及一種繁衍帶有雙向信息傳遞通道node實(shí)例的特殊辦法。
- node內(nèi)置了調(diào)試器呈野,控制臺輸入node debug app.js可以分步調(diào)試程序低矮,n(下一步)、s(步入)被冒、o(步出)军掂。n會跨過當(dāng)前行:調(diào)試器會執(zhí)行這一行,但如果指令調(diào)用了其他函數(shù)昨悼,在這些函數(shù)執(zhí)行完后才把控制權(quán)交還良姆。s與之不同,如果調(diào)用其他函數(shù)會進(jìn)入函數(shù)內(nèi)部逐步執(zhí)行幔戏。o允許跳出當(dāng)前正在執(zhí)行的函數(shù)玛追。
- 也可以使用node探查器node-inspector,可以在瀏覽器內(nèi)逐步調(diào)試。
node的異步I/O
事件循環(huán)是異步實(shí)現(xiàn)的核心闲延,它與瀏覽器中的執(zhí)行模型基本保持一致痊剖。
在啟動node進(jìn)程時會創(chuàng)建一個類似while(true)的循環(huán),每執(zhí)行一次循環(huán)體的過程我們稱之為Tick垒玲。每個Tick的過程就是查看是否有事件待處理陆馁,如果有,就取出事件及其相關(guān)的回調(diào)函數(shù)合愈。如果存在關(guān)聯(lián)的回調(diào)函數(shù)叮贩,就執(zhí)行他們。然后進(jìn)入下一個循環(huán)佛析,如果不再有事件處理益老,就退出進(jìn)程。
事件循環(huán)是一個典型的生產(chǎn)者/消費(fèi)者模型寸莫。異步I/O捺萌、網(wǎng)絡(luò)請求等則是事件的生產(chǎn)者,源源不斷為Node提供不同類型的事件膘茎,這些事件被傳遞到對應(yīng)的觀察者那里桃纯,事件循環(huán)則從觀察者那里取出事件并處理酷誓。
-
事實(shí)上,在node中态坦,除了javascript是單線程的盐数,Node本身其實(shí)是多線程的,只是I/O線程使用的CPU較少伞梯。除了用戶代碼無法并行執(zhí)行外玫氢,所有的I/O(磁盤I/O和網(wǎng)絡(luò)I/O等)是可以并行起來的。
非I/O的api setTimeout和setInterval
- 定時器的問題在于它并非精準(zhǔn)的(在容忍范圍內(nèi))壮锻。如果一次循環(huán)占用的時間過多琐旁,那么下次循環(huán)時可能會超時涮阔。如通過setTimeout設(shè)置一個任務(wù)在10毫秒之后執(zhí)行猜绣,但是在9毫秒后,有個任務(wù)占用了5毫秒的CPU時間片敬特,再次輪到定時器執(zhí)行時掰邢,時間就已經(jīng)過期四毫秒。
Buffer對象
Buffer對象類似于數(shù)組伟阔,它的元素為16進(jìn)制的兩位數(shù)辣之,即0~255的數(shù)值。
Bufffer可以對字符串的編碼進(jìn)行轉(zhuǎn)換皱炉,通過字符串創(chuàng)建一個buffer:new Buffer(str怀估,[encoding]);若encoding不傳值默認(rèn)utf8編碼。
buffer轉(zhuǎn)出字符串合搅,利用buffer.tostring([encoding],[start],[end]);
在傳輸數(shù)據(jù)時經(jīng)常使用trunk來表示表示buffer數(shù)據(jù)多搀,data+=trunk;等價于data=data.tostring()+trunk.tostring();這個適用于傳輸內(nèi)容為英文的數(shù)據(jù)灾部,中文uft8編碼中占三個字節(jié)康铭,如果中間隔開會出現(xiàn)亂碼。
如果是socket通信則可以使用socket.setEncoding([encoding])來設(shè)置接受數(shù)據(jù)的編碼格式赌髓。
-
為了不亂碼从藤,buffer的正確拼接方式是用一個數(shù)組來存儲接收所有Buffer片段并記錄下所有片段的總長度,然后調(diào)用數(shù)組的Buffer.concat()方法生成一個合并的buffer對象
var chunks = [];
var size = 0;
res.on('data', function (chunk) {
chunks.push(chunk);
size += chunk.length;
});
res.on('end', function () {
var data = null;
switch(chunks.length) {
case 0: data = new Buffer(0);
break;
case 1: data = chunks[0];
break;
default:
data = new Buffer(size);
for (var i = 0, pos = 0, l = chunks.length; i < l; i++) {
var chunk = chunks[i];
chunk.copy(data, pos);
pos += chunk.length;
}
break;
}
});
```
函數(shù)式編程
高階函數(shù)
- 高階函數(shù)可以將函數(shù)作為輸入或者返回值锁蠕,事件的回調(diào)處理是基于高階函數(shù)的特性來完成的夷野。高階函數(shù)可以讓事件十分方便地進(jìn)行復(fù)雜業(yè)務(wù)邏輯的解耦。
- 偏函數(shù)用法是指創(chuàng)建一個調(diào)用另外一個部分——參數(shù)或變量已經(jīng)預(yù)制的函數(shù)——的函數(shù)的用法荣倾。實(shí)現(xiàn)方法類似于工廠模式通過指定部分參數(shù)來產(chǎn)生一個新的定制函數(shù)扫责。
偏函數(shù)
偏函數(shù)你可以理解為工廠函數(shù),也就是這種函數(shù)是用來當(dāng)做模板來生產(chǎn)出函數(shù)的逃呼,因為作為一等公民鳖孤,函數(shù)可以作為返回值者娱。
-
一個javascript對類型的判斷的例子:
var toString = Object.prototype.toString; var isString = function (obj){ return toString.call(obj) == '[object String]'; }; var isFunction = function(obj){ return toString.call(obj) == '[object Function]'; };
網(wǎng)絡(luò)通信
REST API
API與用戶的通信協(xié)議,總是使用HTTPs協(xié)議苏揣。
應(yīng)該盡量將API部署在專用域名之下黄鳍,或者主域名下:https://example.org/api/
應(yīng)該將API的版本號放入URL:https://api.example.com/v1/
網(wǎng)址中不能有動詞,只能有名詞平匈,而且所用的名詞往往與數(shù)據(jù)庫的表格名對應(yīng)框沟。一般來說,數(shù)據(jù)庫中的表都是同種記錄的"集合"(collection)增炭,所以API中的名詞也應(yīng)該使用復(fù)數(shù)忍燥。
-
對于資源的具體操作類型,由HTTP動詞表示隙姿。常用的HTTP動詞有下面五個(括號里是對應(yīng)的SQL命令)梅垄。
GET(SELECT):從服務(wù)器取出資源(一項或多項) POST(CREATE):在服務(wù)器新建一個資源 PUT(UPDATE):在服務(wù)器更新資源(客戶端提供改變后的完整資源) PATCH(UPDATE):在服務(wù)器更新資源(客戶端提供改變的屬性) DELETE(DELETE):從服務(wù)器刪除資源
-
如果記錄數(shù)量很多,服務(wù)器不可能都將它們返回給用戶输玷。API應(yīng)該提供參數(shù)队丝,過濾返回結(jié)果。
下面是一些常見的參數(shù)欲鹏。?limit=10:指定返回記錄的數(shù)量 ?offset=10:指定返回記錄的開始位置机久。 ?page=2&per_page=100:指定第幾頁,以及每頁的記錄數(shù)赔嚎。 ?sortby=name&order=asc:指定返回結(jié)果按照哪個屬性排序膘盖,以及排序順序。 ?animal_type_id=1:指定篩選條件
-
服務(wù)器向用戶返回的狀態(tài)碼和提示信息尤误,常見的有以下一些(方括號中是該狀態(tài)碼對應(yīng)的HTTP動詞)
200 OK - [GET]:服務(wù)器成功返回用戶請求的數(shù)據(jù)侠畔,該操作是冪等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數(shù)據(jù)成功袄膏。 202 Accepted - [*]:表示一個請求已經(jīng)進(jìn)入后臺排隊(異步任務(wù)) 204 NO CONTENT - [DELETE]:用戶刪除數(shù)據(jù)成功践图。 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤,服務(wù)器沒有進(jìn)行新建或修改數(shù)據(jù)的操作沉馆,該操作是冪等的码党。 401 Unauthorized - [*]:表示用戶沒有權(quán)限(令牌、用戶名斥黑、密碼錯誤)揖盘。 403 Forbidden - [*] 表示用戶得到授權(quán)(與401錯誤相對),但是訪問是被禁止的锌奴。 404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄兽狭,服務(wù)器沒有進(jìn)行操作,該操作是冪等的。 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用戶請求的資源被永久刪除劝篷,且不會再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 當(dāng)創(chuàng)建一個對象時斩熊,發(fā)生一個驗證錯誤。 500 INTERNAL SERVER ERROR - [*]:服務(wù)器發(fā)生錯誤伐庭,用戶將無法判斷發(fā)出的請求是否成功粉渠。
-
針對不同操作,服務(wù)器向用戶返回的結(jié)果應(yīng)該符合以下規(guī)范圾另。
GET /collection:返回資源對象的列表(數(shù)組) GET /collection/resource:返回單個資源對象 POST /collection:返回新生成的資源對象 PUT /collection/resource:返回完整的資源對象 PATCH /collection/resource:返回完整的資源對象 DELETE /collection/resource:返回一個空文檔
RESTful API最好做到Hypermedia霸株,即返回結(jié)果中提供鏈接,連向其他API方法集乔,使得用戶不查文檔去件,也知道下一步應(yīng)該做什么。
node提供net饺著、dgram箫攀、http肠牲、https模塊來創(chuàng)建TCP幼衰、UDP、HTTP缀雳、HTTPS服務(wù)器渡嚣。
webSocket
- 瀏覽器通過在請求頭中添加Upgrade:webSockt和Connection:Upgrade來表示請求服務(wù)器端升級協(xié)議為websockt。通常使用Sec-WebSockt-Key用于安全校驗肥印。
HTTPS
- SSL作為一種安全協(xié)議识椰,在傳輸層提供對網(wǎng)絡(luò)連接加密的功能,對應(yīng)用層而言是透明的深碱,數(shù)據(jù)在傳遞到應(yīng)用層之前就已經(jīng)完成了加密和解密的過程腹鹉。
- node在網(wǎng)絡(luò)安全方面提供了三個模塊:
- crypto主要用于加密解密,SHA1和MD5等算法敷硅。
- tls提供了與net模塊類似的功能功咒,區(qū)別在于建立的是TLS/SSL加密的TCP連接上。
- https與http模塊接口一致绞蹦,區(qū)別在于建立安全的連接力奋。
Node使用
在node中定義了靜態(tài)文件app.use(express.static(path))之后如果要用里面數(shù)據(jù)可以直接使用以/開頭的靜態(tài)文件相對路徑。
node刪除file使用fs.unlink( )!
node中fs.stat( )系統(tǒng)調(diào)用獲取文件的相關(guān)信息幽七,比如修改時間景殷、字節(jié)數(shù)等,如果文件不存在fs.stat()會在err.code中放入ENOOENT作為響應(yīng)。
app.use('/api',api.auth)這是掛載點(diǎn)猿挚,即任何以/api開頭的請求路徑名和HTTP謂詞都會導(dǎo)致這個中間件被調(diào)用咐旧。
-
node中引入crypto模塊用于加密
function sha1(str){
var md5sum = crypto.createHash("sha1");
md5sum.update(str);
str = md5sum.digest("hex");
return str;
}
```
模塊內(nèi)引用路徑時一定要使用絕對路徑,借助于全局變量__dirname與__filename來使用绩蜻。因為當(dāng)主函數(shù)使用模塊時若是相對路徑則以主函數(shù)作為參考休偶。
標(biāo)準(zhǔn)庫組件url可以補(bǔ)全地址url.resolve(主站url,href)辜羊。
node中的全局函數(shù)process.argv為一個argument的數(shù)組索引為零的儲存的是node所在文件夾踏兜,索引為1的是當(dāng)前執(zhí)行文件路徑,后面的索引為在命令行啟動node時傳入的參數(shù)八秃。
模塊導(dǎo)出時用module.exports={函數(shù)名}的形式碱妆,導(dǎo)入模塊時即使在同一目錄下也需要在開頭加“./文件名.js”若不加./則優(yōu)先在內(nèi)置模塊中尋找,然后是在node_modules文件夾中尋找昔驱。
絕大部分node異步API接收的回調(diào)函數(shù)疹尾,第一個參數(shù)都是錯誤對象或者是null。
-
Event模塊時node對‘發(fā)布/訂閱’模式的實(shí)現(xiàn)骤肛,其中提供了一個EventEmitter對象纳本,核心事件就是事件的觸發(fā)與事件監(jiān)聽功能的封裝。
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter; //初始化對象
emitter.on(‘自定義事件名’腋颠,function(){}) //綁定事件
emitter.emit(‘事件名’繁成,‘回調(diào)函數(shù)的參數(shù)’) // 觸發(fā)事件
```
- 使用net.creatServer( function(socket){})時候回調(diào)函數(shù)傳回來的是一個socket對象,可以通過給socket對象setEncoding來設(shè)置接收到的流的顯示方式淑玫。socket.on(‘data’,回調(diào)函數(shù))來給socket綁定接受到數(shù)據(jù)時觸發(fā)的事件巾腕。
- fs.createReadStream('fire.jpg').pipe(respond);在http中通過流的方式給頁面中傳圖片。
- node中http會將所有主機(jī)名后面的內(nèi)容放入request.url中.
- node提供querystring的模塊絮蒿,該模塊含有一個.parse( )方法尊搬,傳入?yún)?shù)如“q=1”的字符串返回一個{q:1}的對象。這個解析處理方式和Node解析header消息的方法類似土涝,node將http請求數(shù)據(jù)中的header信息從字符串解析成一個方便處理的header對象佛寿。同樣可以使用querystring.stringfy({q:1})將對象轉(zhuǎn)為字符串。
- 在http的請求中一般通過給respond綁定data事件來獲取返回的數(shù)據(jù)但壮,綁定end事件等待數(shù)據(jù)獲取完后執(zhí)行相應(yīng)操作冀泻。
- node在設(shè)置登錄頁面時,如果用到了第三方認(rèn)證如微博QQ等登錄可以使用passport模塊茵肃,方便配置各種類型的OAuth腔长。
- express客戶端使用socket.io要引入socket.io給客戶端寫的js文件<script src='/socket.io/socket.io.js'></script>
- express中使用socket.io模塊,如果要群發(fā)信息則需要每個客戶端都加入到同一房間內(nèi)验残,使用socket.join(‘房間名’)捞附;來加入房間,然后使用socket.to(‘房間名’).emit(‘event’,fn)來廣播消息鸟召,消息默認(rèn)只對除當(dāng)前客戶端之外的所有客戶端發(fā)送胆绊,如果還要對當(dāng)前客戶端發(fā)送則再加上socket.emit(‘event’,fn)∨纺迹可以利用socket.rooms來查看客戶端所在的房間压状,返回一個對象。一個客戶端可以在多個房間跟继,第一個房間與客戶端的id相同种冬,是一個隨機(jī)的字符串,如果要針對某個客戶端單獨(dú)發(fā)消息可以用to指向客戶端所對應(yīng)的專屬房間舔糖。
- express中路由和中間件的添加順序至關(guān)重要娱两,如果把404處理器放在所有路由上面,首頁和相關(guān)頁面就無法顯示金吗。自己編寫中間件時如果方法后面沒有調(diào)用next()則不會再執(zhí)行之后的中間件十兢。使用app.use(‘/url’,中間件),第一個參數(shù)表示當(dāng)url前綴與之匹配是才會調(diào)用后面的中間件摇庙。
- bodyParser()組件用于解析POST請求旱物,它提供了req.body屬性,可以用來解析注冊信息如JSON卫袒、x-www-form-urlencoded(HTML表單的默認(rèn)值)和multipart/form-data請求宵呛。如果是multipart/form-data請求,如文件上傳玛臂,則還有req.files對象烤蜕。
- query()組件主要用于解析GET請求封孙,它提供req.query對象將url中的GET數(shù)據(jù)轉(zhuǎn)化成一個對象存在req.query中迹冤。
- cheerio組件為一個 Node.js 版的 jquery,用來從網(wǎng)頁中以 css selector 取數(shù)據(jù)虎忌,使用方式跟 jquery 一樣一樣的泡徙。在爬蟲應(yīng)用中使用superagent.get()得到網(wǎng)頁的數(shù)據(jù)srea之后利用cheerio 來將數(shù)據(jù)解析var $ = cheerio.load(sres.text);之后通過$(‘.’)方式來獲取DOM。
- 一定要注意superagent使用的是異步請求膜蠢,會在發(fā)送去請求后繼續(xù)執(zhí)行下面代碼而非在獲得請求結(jié)果后堪藐。
- 利用eventproxy組件針對多個異步請求統(tǒng)一處理回調(diào)函數(shù),無深度嵌套挑围。用來檢測多個異步操作是否完成礁竞,完成之后,會自動調(diào)用處理函數(shù)杉辙,并將抓取到的數(shù)據(jù)當(dāng)參數(shù)傳過來模捂。
- 當(dāng)你需要去多個源(一般是小于 10 個)匯總數(shù)據(jù)的時候,用 eventproxy 方便;當(dāng)你需要用到隊列狂男,需要控制并發(fā)數(shù)综看,或者你喜歡函數(shù)式編程思維時,使用 async做異步處理岖食。
- nodemon這個庫是專門調(diào)試時候使用的红碑,它會自動檢測node.js 代碼的改動,然后幫你自動重啟應(yīng)用泡垃。在調(diào)試時可以完全用 nodemon 命令代替 node 命令析珊。$ nodemon app.js 啟動應(yīng)用。
- 上傳大型文件時可以使用formidable的流式解析器蔑穴,它可以隨著數(shù)據(jù)塊的上傳接收它們并呈現(xiàn)特定的部分這種方式不僅快唾琼,還不會因為需要大量的緩沖而導(dǎo)致內(nèi)存膨脹,即便像視頻這種大型文件澎剥,也不會把進(jìn)程壓垮锡溯。
- 管理用戶密碼文件時所謂加Salt,就是加點(diǎn)“佐料”哑姚。當(dāng)用戶首次提供密碼時(通常是注冊時)祭饭,由系統(tǒng)自動往這個密碼里加一些“Salt值”,這個值是由系統(tǒng)隨機(jī)生成的叙量,并且只有系統(tǒng)知道倡蝙。然后再散列。而當(dāng)用戶登錄時绞佩,系統(tǒng)為用戶提供的代碼撒上同樣的“Salt值”寺鸥,然后散列,再比較散列值品山,已確定密碼是否正確胆建。這樣,即便兩個用戶使用了同一個密碼肘交,由于系統(tǒng)為它們生成的salt值不同笆载,他們的散列值也是不同的。即便黑客可以通過自己的密碼和自己生成的散列值來找具有特定密碼的用戶涯呻,但這個幾率太小了(密碼和salt值都得和黑客使用的一樣才行)凉驻。參看express的auth示例。
- Post/Redirect/Get(PRG)模式是一個常用的web程序設(shè)計模式复罐。在這種模式中涝登,用戶請求表單,用HTTP/POST請求表單數(shù)據(jù)效诅,然后用戶被重定向到另外一個web頁面上胀滚。被重定向到哪里取決于表單數(shù)據(jù)是否有效咳短。如果表單數(shù)據(jù)無效,程序會讓用戶回到表單頁面蛛淋。如果表單數(shù)據(jù)有效咙好,程序會讓用戶到新的頁面中。PRG模式主要是為了防止表單的重復(fù)提交褐荷。
- 在express中用戶被重定向后勾效,res.locals中的內(nèi)容會被重置。Server傳來消息最好存在會話變量中叛甫。res.message函數(shù)可以吧消息添加到任何Express請求的會話變量中层宫。
- express.response對象是Express給相應(yīng)對象的原型,向這個對象中添加屬性意味著所有的中間件和路由都能訪問它們其监。
- 使用res.redirect()時第一個參數(shù)可以填HTTP的Status Code萌腿,301重定向是“永久”的,意味著瀏覽器會緩存重定向目標(biāo)抖苦。如果使用301重定向并試圖第二次提交表單毁菱,瀏覽器會繞過整個處理程序并直接進(jìn)入相應(yīng)頁面。使用303重定向不會緩存重定向目標(biāo)锌历。默認(rèn)是302重定向贮庞。
- http中結(jié)束一次會話后記得調(diào)用res.end()結(jié)束請求,否則客戶端將一直處于等待狀態(tài)究西。
Async庫
Async庫是為了處理nodejs中的異步任務(wù)窗慎,同樣也可以設(shè)置任務(wù)的同步執(zhí)行流程。
使用async調(diào)用的函數(shù)必須是有一個callback參數(shù)卤材,并在函數(shù)執(zhí)行完后調(diào)用callback(null, "done!");第一個參數(shù)是error參數(shù)遮斥。如果任何一個函數(shù)向它的回調(diào)函數(shù)中傳了一個error,則后面的函數(shù)都不會被執(zhí)行扇丛,并且將會立刻會將該error以及已經(jīng)執(zhí)行了的函數(shù)的結(jié)果术吗,傳給series中最后那個callback。
- series(tasks, [callback]) (多個函數(shù)依次執(zhí)行晕拆,之間沒有數(shù)據(jù)交換)
- waterfall(tasks, [callback]) (多個函數(shù)依次執(zhí)行藐翎,且前一個的輸出為后一個的輸入)
- parallel(tasks, [callback]) (多個函數(shù)并行執(zhí)行)
- auto(tasks, [callback]) (多個函數(shù)有依賴關(guān)系,有的并行執(zhí)行实幕,有的依次執(zhí)行)
- whilst(test, fn, callback)(用可于異步調(diào)用的while)
BasicAuth庫
- basicAuth中間件為網(wǎng)站添加身份認(rèn)證功能,使用該中間件后堤器,用戶訪問網(wǎng)站必須輸入用戶名和密碼并通過難后才能訪問網(wǎng)站昆庇。只提供最基本的訪問授權(quán),并且只能通過HTTPS使用闸溃。只有在需要又快又容易的東西整吆,并且在HTTPS時才用到BasicAuth拱撵。
路由參數(shù)
app.get(/staff/:name,function(){})
node中路由系統(tǒng)會將參數(shù)值放入req.params.name中。
ejs模板
- 使用render來渲染輸出模板:ejs.render(str, data, options); // render的返回值是最終結(jié)果string
- ejs中循環(huán)輸出
<ul>
<% names.forEach(function(name){ %>
<li><%= name %></li>
<% }) %>
</ul>
options
```
cache:true, //是否對結(jié)果進(jìn)行緩存(需要filename)
filename:"path", //cache的key表蝙,用于include指令中
scope:"this", //指定函數(shù)執(zhí)行的上下文對象
debug:true, //輸出生成的函數(shù)體
compileDebug:false, //為false時拴测,debug指令不會被編譯
client:"", //返回獨(dú)立的編譯后的函數(shù)
open:"<%", //指定開標(biāo)簽
close:"%>", //指定閉標(biāo)簽
```
如果定義了一段ejs模板作為公共模板,現(xiàn)在想引用這段公共模板的話府蛇,可以用include指令集索,需要在options里指定filename和傳入?yún)?shù):include('user/show', {user: user})
-
過濾器:用于將結(jié)果進(jìn)一步加工的API:
<p><%=: users | map:'name' | join %></p> //注意起始的:和中間的|標(biāo)記
ejs.render(str, {
users: [
{ name: 'tj' },
{ name: 'mape' },
{ name: 'guillermo' }
]
});
// 結(jié)果是:<p>Tj, Mape, Guillermo</p>
child_process模塊中的spawn和exec方法
這兩個方法都可以被用來開啟一個子進(jìn)程來執(zhí)行其他的程序.
child_process.spaen會返回一個帶有stdout和stderr流的對象。你可以通過stdout流來讀取子進(jìn)程返回給Node.js的數(shù)據(jù)汇跨。stdout擁有’data’,’end’以及一般流所具有的事件务荆。當(dāng)你想要子進(jìn)程返回大量數(shù)據(jù)給Node時,比如說圖像處理穷遂,讀取二進(jìn)制數(shù)據(jù)等等函匕,你最好使用spawn方法。
child_process.spawn方法是“異步中的異步”蚪黑,意思是在子進(jìn)程開始執(zhí)行時盅惜,它就開始從一個流總將數(shù)據(jù)從子進(jìn)程返回給Node。
-
比如說我們想從一個URL下載文件忌穿,我們選擇使用curl工具酷窥,此時,我們就可以在Node中使用spawn運(yùn)行curl工具伴网,下面是具體代碼:
var file = fs.createWriteStream(DOWNLOAD_DIR + file_name); var curl = spawn('curl', [file_url]); // 為spawn實(shí)例添加了一個data事件 curl.stdout.on('data', function(data) { file.write(data); }); // 添加一個end監(jiān)聽器來關(guān)閉文件流 curl.stdout.on('end', function(data) { file.end(); console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR); }); // 當(dāng)子進(jìn)程退出時蓬推,檢查是否有錯誤,同時關(guān)閉文件流 curl.on('exit', function(code) { if (code != 0) { console.log('Failed: ' + code); } });
child_process.exec方法會從子進(jìn)程中返回一個完整的buffer澡腾。默認(rèn)情況下沸伏,這個buffer的大小應(yīng)該是200k。如果子進(jìn)程返回的數(shù)據(jù)大小超過了200k动分,程序?qū)罎⒁阍悖瑫r顯示錯誤信息“Error:maxBuffer exceeded”。
-
child_process.exec方法是“同步中的異步”澜公,盡管exec是異步的姆另,它一定要等到子進(jìn)程運(yùn)行結(jié)束以后然后一次性返回所有的buffer數(shù)據(jù)。如果exec的buffer體積設(shè)置的不夠大坟乾,它將會以一個“maxBuffer exceeded”錯誤失敗告終迹辐。
var child = exec(cmomand, function(err, stdout, stderr) { if (err) throw err; else console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR); });
爬蟲
- __VIEWSTATE
a) ViewState是ASP.NET中用來保存WEB控件回傳時狀態(tài)值一種機(jī)制。在WEB窗體(FORM)的設(shè)置為runat="server",這個窗體(FORM)會被附加一個隱藏的屬性_VIEWSTATE甚侣。_VIEWSTATE中存放了所有控件在ViewState中的狀態(tài)值明吩。 ViewState是類Control中的一個域,其他所有控件通過繼承Control來獲得了ViewState功能殷费。它的類型是system.Web.UI.StateBag印荔,一個名稱/值的對象集合低葫。
b) 當(dāng)請求某個頁面時,ASP.NET把所有控件的狀態(tài)序列化成一個字符串仍律,然后做為窗體的隱藏屬性送到客戶端嘿悬。當(dāng)客戶端把頁面回傳時,ASP.NET分析回傳的窗體屬性水泉,并賦給控件對應(yīng)的值善涨。 - __EVENTVALIDATION
__EVENTVALIDATION只是用來驗證事件是否從合法的頁面發(fā)送,只是一個數(shù)字簽名茶行,所以一般很短躯概。“id”屬性為“__EVENTVALIDATION”的隱藏字段是ASP.NET 2.0的新增的安全措施畔师。該功能可以阻止由潛在的惡意用戶從瀏覽器端發(fā)送的未經(jīng)授權(quán)的請求.
為了確保每個回發(fā)和回調(diào)事件來自于所期望的用戶界面元素娶靡,ASP.NET運(yùn)行庫將在事件中添加額外的驗證層。服務(wù)器端通過檢驗表單提交請求的內(nèi)容看锉,將其與“id”屬性為“__EVENTVALIDATION”隱藏字段中的信息進(jìn)行匹配姿锭。根據(jù)匹配結(jié)果來驗證未在瀏覽器端添加額外的輸入字段(有可能為用戶在瀏覽器端惡意添加的字段),并且該值是在服務(wù)器已知的列表中選擇的伯铣。ASP.NET運(yùn)行庫將在生成期間創(chuàng)建事件驗證字段呻此,而這是最不可能獲取該信息的時刻。像視圖狀態(tài)一樣腔寡,事件驗證字段包含散列值以防止發(fā)生瀏覽器端篡改焚鲜。
說明:“id”屬性為“__EVENTVALIDATION”隱藏字段一般在表單的最下方,如果表單在瀏覽器端尚未解析完畢時放前,用戶提交數(shù)據(jù)有可能導(dǎo)致驗證失敗忿磅。__EVENTVALIDATION與__VIEWSTATE一般可以在瀏覽器頁面源代碼中找到,作為form中被隱藏的標(biāo)簽凭语,與其他數(shù)據(jù)一同提交葱她。 - 使用superagent得到response的cookie: JSON.stringify(res.header["set-cookie"]);
- 針對superagent獲取的網(wǎng)頁亂碼的情況,superagent-charset擴(kuò)展了superagent的功能似扔,使其可以手動指定編碼功能吨些。
- MD5加密是一種不可逆加密算法,使用MD5加密時相同內(nèi)容以字符串傳入與數(shù)字傳入得到的結(jié)果不同炒辉。