Nodejs筆記

Node基本

  1. node的最大特性莫過于基于事件驅(qū)動的非阻塞I/O模型。
  2. node通過事件驅(qū)動的方式處理請求,無須為每一個請求創(chuàng)建額外的對應(yīng)線程,可以省掉創(chuàng)建線程和銷毀線程的開銷,同時操作系統(tǒng)在調(diào)度任務(wù)時因為線程較少,上下文切換的代價很低。這使得服務(wù)器能夠有條不紊地處理請求,即使在大量連接的情況下,也不受線程上下文切換開銷的影響,這是Node高性能的一個原因。Apache會為每個請求啟動一個線程,每個線程會占用一定內(nèi)存,并發(fā)量較大時會緩慢。Nginx也使用和node一樣的事件驅(qū)動方式處理請求。
  3. node對引入過的模塊都會進(jìn)行緩存,以減少二次引入時的開銷,node緩存的是編譯和執(zhí)行后的對象。不論是核心模塊還是文件模塊,require( )方法對相同模塊的二次加載都一律采用緩存優(yōu)先的方式,這是第一優(yōu)先級的。不同之處在于核心模塊的緩存檢查先于文件模塊的緩存檢查。
  4. 事件輪詢:從本質(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ù)。
  5. 在程序中定義配置項如app.set(“photo”,__dirname+’/public/photos’)后就可以在各種環(huán)境下任意改變此目錄。
  6. 當(dāng)node接收到從瀏覽器發(fā)來的http請求時,底層的TCP連接會分配一個文件描述符。隨后,如果客戶端向服務(wù)器發(fā)送數(shù)據(jù),node就會收到該文件描述符上的通知,然后觸發(fā)JavaScript的回調(diào)函數(shù)。
  7. 對于阻塞式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ā)性。
  8. buffer是一個表示固定內(nèi)存分配的全局對象(即放到緩沖區(qū)的字節(jié)數(shù)需要提前確定)
  9. node的HTTP服務(wù)器是構(gòu)建于node TCP服務(wù)器之上的,即node中的HTTP.server繼承自net.server(net為TCP模塊)。TCP的首要特性是它面向連接。
  10. Node中的管道可以讓數(shù)據(jù)流動到指定目的地(即WriteableStream)讀取一個文件并寫入到另一個文件中,利用pipe()作為連接,ReadableStream.pipe(WriteableStream).HTTP請求中在客戶端request就是一個WriteableStream,response為Readablestream,而在服務(wù)器端則相反。
  11. node與操作系統(tǒng)交互的工具
    • 全局的process對象————包含當(dāng)前進(jìn)程的相關(guān)信息,如傳參和當(dāng)前設(shè)定的環(huán)境變量
    • fs模塊————包含底層的ReadStream和WriteStream類。
    • child_process模塊————繁衍子進(jìn)程的底層和高層接口,以及一種繁衍帶有雙向信息傳遞通道node實例的特殊辦法。
  12. 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ù)。
  13. 也可以使用node探查器node-inspector,可以在瀏覽器內(nèi)逐步調(diào)試。

node的異步I/O

  • 事件循環(huán)是異步實現(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)則從觀察者那里取出事件并處理。

  • 事實上,在node中,除了javascript是單線程的,Node本身其實是多線程的,只是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ù)的用法。實現(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使用

  1. 在node中定義了靜態(tài)文件app.use(express.static(path))之后如果要用里面數(shù)據(jù)可以直接使用以/開頭的靜態(tài)文件相對路徑。

  2. node刪除file使用fs.unlink( )!

  3. node中fs.stat( )系統(tǒng)調(diào)用獲取文件的相關(guān)信息,比如修改時間、字節(jié)數(shù)等,如果文件不存在fs.stat()會在err.code中放入ENOOENT作為響應(yīng)。

  4. app.use('/api',api.auth)這是掛載點,即任何以/api開頭的請求路徑名和HTTP謂詞都會導(dǎo)致這個中間件被調(diào)用。

  5. node中引入crypto模塊用于加密

    function sha1(str){
    

var md5sum = crypto.createHash("sha1");
md5sum.update(str);
str = md5sum.digest("hex");
return str;
}

```
  1. 模塊內(nèi)引用路徑時一定要使用絕對路徑,借助于全局變量__dirname與__filename來使用。因為當(dāng)主函數(shù)使用模塊時若是相對路徑則以主函數(shù)作為參考。

  2. 標(biāo)準(zhǔn)庫組件url可以補(bǔ)全地址url.resolve(主站url,href)。

  3. node中的全局函數(shù)process.argv為一個argument的數(shù)組索引為零的儲存的是node所在文件夾,索引為1的是當(dāng)前執(zhí)行文件路徑,后面的索引為在命令行啟動node時傳入的參數(shù)。

  4. 模塊導(dǎo)出時用module.exports={函數(shù)名}的形式,導(dǎo)入模塊時即使在同一目錄下也需要在開頭加“./文件名.js”若不加./則優(yōu)先在內(nèi)置模塊中尋找,然后是在node_modules文件夾中尋找。

  5. 絕大部分node異步API接收的回調(diào)函數(shù),第一個參數(shù)都是錯誤對象或者是null。

  6. Event模塊時node對‘發(fā)布/訂閱’模式的實現(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ā)事件
```

  1. 使用net.creatServer( function(socket){})時候回調(diào)函數(shù)傳回來的是一個socket對象,可以通過給socket對象setEncoding來設(shè)置接收到的流的顯示方式。socket.on(‘data’,回調(diào)函數(shù))來給socket綁定接受到數(shù)據(jù)時觸發(fā)的事件。
  2. fs.createReadStream('fire.jpg').pipe(respond);在http中通過流的方式給頁面中傳圖片。
  3. node中http會將所有主機(jī)名后面的內(nèi)容放入request.url中.
  4. node提供querystring的模塊,該模塊含有一個.parse( )方法,傳入?yún)?shù)如“q=1”的字符串返回一個{q:1}的對象。這個解析處理方式和Node解析header消息的方法類似,node將http請求數(shù)據(jù)中的header信息從字符串解析成一個方便處理的header對象。同樣可以使用querystring.stringfy({q:1})將對象轉(zhuǎn)為字符串。
  5. 在http的請求中一般通過給respond綁定data事件來獲取返回的數(shù)據(jù),綁定end事件等待數(shù)據(jù)獲取完后執(zhí)行相應(yīng)操作。
  6. node在設(shè)置登錄頁面時,如果用到了第三方認(rèn)證如微博QQ等登錄可以使用passport模塊,方便配置各種類型的OAuth。
  7. express客戶端使用socket.io要引入socket.io給客戶端寫的js文件<script src='/socket.io/socket.io.js'></script>
  8. 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)??梢岳胹ocket.rooms來查看客戶端所在的房間,返回一個對象。一個客戶端可以在多個房間,第一個房間與客戶端的id相同,是一個隨機(jī)的字符串,如果要針對某個客戶端單獨發(fā)消息可以用to指向客戶端所對應(yīng)的專屬房間。
  9. express中路由和中間件的添加順序至關(guān)重要,如果把404處理器放在所有路由上面,首頁和相關(guān)頁面就無法顯示。自己編寫中間件時如果方法后面沒有調(diào)用next()則不會再執(zhí)行之后的中間件。使用app.use(‘/url’,中間件),第一個參數(shù)表示當(dāng)url前綴與之匹配是才會調(diào)用后面的中間件。
  10. bodyParser()組件用于解析POST請求,它提供了req.body屬性,可以用來解析注冊信息如JSON、x-www-form-urlencoded(HTML表單的默認(rèn)值)和multipart/form-data請求。如果是multipart/form-data請求,如文件上傳,則還有req.files對象。
  11. query()組件主要用于解析GET請求,它提供req.query對象將url中的GET數(shù)據(jù)轉(zhuǎn)化成一個對象存在req.query中。
  12. 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。
  13. 一定要注意superagent使用的是異步請求,會在發(fā)送去請求后繼續(xù)執(zhí)行下面代碼而非在獲得請求結(jié)果后。
  14. 利用eventproxy組件針對多個異步請求統(tǒng)一處理回調(diào)函數(shù),無深度嵌套。用來檢測多個異步操作是否完成,完成之后,會自動調(diào)用處理函數(shù),并將抓取到的數(shù)據(jù)當(dāng)參數(shù)傳過來。
  15. 當(dāng)你需要去多個源(一般是小于 10 個)匯總數(shù)據(jù)的時候,用 eventproxy 方便;當(dāng)你需要用到隊列,需要控制并發(fā)數(shù),或者你喜歡函數(shù)式編程思維時,使用 async做異步處理。
  16. nodemon這個庫是專門調(diào)試時候使用的,它會自動檢測node.js 代碼的改動,然后幫你自動重啟應(yīng)用。在調(diào)試時可以完全用 nodemon 命令代替 node 命令。$ nodemon app.js 啟動應(yīng)用。
  17. 上傳大型文件時可以使用formidable的流式解析器,它可以隨著數(shù)據(jù)塊的上傳接收它們并呈現(xiàn)特定的部分這種方式不僅快,還不會因為需要大量的緩沖而導(dǎo)致內(nèi)存膨脹,即便像視頻這種大型文件,也不會把進(jìn)程壓垮。
  18. 管理用戶密碼文件時所謂加Salt,就是加點“佐料”。當(dāng)用戶首次提供密碼時(通常是注冊時),由系統(tǒng)自動往這個密碼里加一些“Salt值”,這個值是由系統(tǒng)隨機(jī)生成的,并且只有系統(tǒng)知道。然后再散列。而當(dāng)用戶登錄時,系統(tǒng)為用戶提供的代碼撒上同樣的“Salt值”,然后散列,再比較散列值,已確定密碼是否正確。這樣,即便兩個用戶使用了同一個密碼,由于系統(tǒng)為它們生成的salt值不同,他們的散列值也是不同的。即便黑客可以通過自己的密碼和自己生成的散列值來找具有特定密碼的用戶,但這個幾率太小了(密碼和salt值都得和黑客使用的一樣才行)。參看express的auth示例。
  19. Post/Redirect/Get(PRG)模式是一個常用的web程序設(shè)計模式。在這種模式中,用戶請求表單,用HTTP/POST請求表單數(shù)據(jù),然后用戶被重定向到另外一個web頁面上。被重定向到哪里取決于表單數(shù)據(jù)是否有效。如果表單數(shù)據(jù)無效,程序會讓用戶回到表單頁面。如果表單數(shù)據(jù)有效,程序會讓用戶到新的頁面中。PRG模式主要是為了防止表單的重復(fù)提交。
  20. 在express中用戶被重定向后,res.locals中的內(nèi)容會被重置。Server傳來消息最好存在會話變量中。res.message函數(shù)可以吧消息添加到任何Express請求的會話變量中。
  21. express.response對象是Express給相應(yīng)對象的原型,向這個對象中添加屬性意味著所有的中間件和路由都能訪問它們。
  22. 使用res.redirect()時第一個參數(shù)可以填HTTP的Status Code,301重定向是“永久”的,意味著瀏覽器會緩存重定向目標(biāo)。如果使用301重定向并試圖第二次提交表單,瀏覽器會繞過整個處理程序并直接進(jìn)入相應(yīng)頁面。使用303重定向不會緩存重定向目標(biāo)。默認(rèn)是302重定向。
  23. 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。

  1. series(tasks, [callback]) (多個函數(shù)依次執(zhí)行,之間沒有數(shù)據(jù)交換)
  2. waterfall(tasks, [callback]) (多個函數(shù)依次執(zhí)行,且前一個的輸出為后一個的輸入)
  3. parallel(tasks, [callback]) (多個函數(shù)并行執(zhí)行)
  4. auto(tasks, [callback]) (多個函數(shù)有依賴關(guān)系,有的并行執(zhí)行,有的依次執(zhí)行)
  5. 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:"", //返回獨立的編譯后的函數(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實例添加了一個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);
    });
    

爬蟲

  1. __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)的值。
  2. __EVENTVALIDATION
    __EVENTVALIDATION只是用來驗證事件是否從合法的頁面發(fā)送,只是一個數(shù)字簽名,所以一般很短?!癷d”屬性為“__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ù)一同提交。
  3. 使用superagent得到response的cookie: JSON.stringify(res.header["set-cookie"]);
  4. 針對superagent獲取的網(wǎng)頁亂碼的情況,superagent-charset擴(kuò)展了superagent的功能,使其可以手動指定編碼功能。
  5. MD5加密是一種不可逆加密算法,使用MD5加密時相同內(nèi)容以字符串傳入與數(shù)字傳入得到的結(jié)果不同。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容