NodeJS學(xué)習(xí)筆記之Http模塊
一,開篇分析
首先“Http”這個概念大家應(yīng)該比較熟悉了,它不是基于特定語言的,是一個通用的應(yīng)用層協(xié)議,不同語言有不同的實現(xiàn)細(xì)節(jié),但是萬變不離其宗,思想是相同的,
NodeJS作為一個宿主運行環(huán)境,以JavaScript為宿主語言,它也有自己實現(xiàn)的一套標(biāo)準(zhǔn),這篇文章我們就一起來學(xué)習(xí)一下 “Http模塊” 。但是作為前提來說,
希望大家可以先閱讀一下官網(wǎng)提供的api,有一個前置了解,這樣就方便多了,以下是Http部分的api概覽:
HTTP
http.STATUS_CODES
http.createServer([requestListener])
http.createClient([port], [host])
Class: http.Server
事件 : 'request'
事件: 'connection'
事件: 'close'
Event: 'checkContinue'
事件: 'connect'
Event: 'upgrade'
Event: 'clientError'
server.listen(port, [hostname], [backlog], [callback])
server.listen(path, [callback])
server.listen(handle, [callback])
server.close([callback])
server.maxHeadersCount
server.setTimeout(msecs, callback)
server.timeout
Class: http.ServerResponse
事件: 'close'
response.writeContinue()
response.writeHead(statusCode, [reasonPhrase], [headers])
response.setTimeout(msecs, callback)
response.statusCode
response.setHeader(name, value)
response.headersSent
response.sendDate
response.getHeader(name)
response.removeHeader(name)
response.write(chunk, [encoding])
response.addTrailers(headers)
response.end([data], [encoding])
http.request(options, callback)
http.get(options, callback)
Class: http.Agent
new Agent([options])
agent.maxSockets
agent.maxFreeSockets
agent.sockets
agent.freeSockets
agent.requests
agent.destroy()
agent.getName(options)
http.globalAgent
Class: http.ClientRequest
Event 'response'
Event: 'socket'
事件: 'connect'
Event: 'upgrade'
Event: 'continue'
request.write(chunk, [encoding])
request.end([data], [encoding])
request.abort()
request.setTimeout(timeout, [callback])
request.setNoDelay([noDelay])
request.setSocketKeepAlive([enable], [initialDelay])
http.IncomingMessage
事件: 'close'
message.httpVersion
message.headers
message.rawHeaders
message.trailers
message.rawTrailers
message.setTimeout(msecs, callback)
message.method
message.url
message.statusCode
message.socket
讓我們先從一個簡單例子開始,創(chuàng)建一個叫server.js的文件,并寫入以下代碼:
var http = require('http') ;
var server = http.createServer(function(req,res){
res.writeHeader(200,{
'Content-Type' : 'text/plain;charset=utf-8' // 添加charset=utf-8
}) ;
res.end("Hello,大熊!") ;
}) ;
server.listen(8888) ;
console.log("http server running on port 8888 ...") ;
(node server.js)以下是運行結(jié)果:
二,細(xì)節(jié)分析實例
具體看一下這個小例子:
(1行):通過"require"引入NodeJS自帶的"http"模塊,并且把它賦值給http變量。
(2行):調(diào)用http模塊提供的函數(shù):"createServer" 。這個函數(shù)會返回一個新的web服務(wù)器對象。
參數(shù) "requestListener" 是一個函數(shù),它將會自動加入到 "request" 事件的監(jiān)聽隊列。
當(dāng)一個request到來時,Event-Loop會將這個Listener回調(diào)函數(shù)放入執(zhí)行隊列, node中所有的代碼都是一個一個從執(zhí)行隊列中拿出來執(zhí)行的。
這些執(zhí)行都是在工作線程上(Event Loop本身可以認(rèn)為在一個獨立的線程中,我們一般不提這個線程,而將node稱呼為一個單線程的執(zhí)行環(huán)境),
所有的回調(diào)都是在一個工作線程上運行。
我們在再來看一下"requestListener"這個回調(diào)函數(shù),它提供了兩個參數(shù)(request,response),
每次收到一個請求時觸發(fā)。注意每個連接又可能有多個請求(在keep-alive的連接中)。
"request"是http.IncomingMessage的一個實例。"response"是http.ServerResponse的一個實例。
一個http request對象是可讀流,而http response對象則是可寫流。
一個"IncomingMessage"對象是由http.Server或http.ClientRequest創(chuàng)建的,
并作為第一參數(shù)分別傳遞給"request"和"response"事件。
它也可以被用來訪問應(yīng)答的狀態(tài),頭文件和數(shù)據(jù)。
它實現(xiàn)了 "Stream" 接口以及以下額外的事件,方法和屬性。(具體參考api)。
(3行):“writeHeader”,使用 "response.writeHead()" 函數(shù)發(fā)送一個Http狀態(tài)200和Http頭的內(nèi)容類型(content-type)。
向請求回復(fù)響應(yīng)頭。"statusCode"是一個三位是的HTTP狀態(tài)碼,例如 404 。最后一個參數(shù),"headers",是響應(yīng)頭的內(nèi)容。
舉個栗子:
var body = 'hello world' ;
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
}) ;
注意:Content-Length 是以字節(jié)(byte)計算,而不是以字符(character)計算。
之前的例子原因是字符串 “Hello World !” 只包含了單字節(jié)的字符。
如果body包含了多字節(jié)編碼的字符,就應(yīng)當(dāng)使用Buffer.byteLength()來確定在多字節(jié)字符編碼情況下字符串的字節(jié)數(shù)。
需要進一步說明的是Node不檢查Content-Lenth屬性和已傳輸?shù)腷ody長度是否吻合。
statusCode是一個三位是的HTTP狀態(tài)碼, 例如:"404" 。這里要說的是 "http.STATUS_CODES" ,全部標(biāo)準(zhǔn)"Http"響應(yīng)狀態(tài)碼的集合和簡短描述都在里面。
如下是源碼參考:
var STATUS_CODES = exports.STATUS_CODES = {
100 : 'Continue',
101 : 'Switching Protocols',
102 : 'Processing', // RFC 2518, obsoleted by RFC 4918
200 : 'OK',
201 : 'Created',
202 : 'Accepted',
203 : 'Non-Authoritative Information',
204 : 'No Content',
205 : 'Reset Content',
206 : 'Partial Content',
207 : 'Multi-Status', // RFC 4918
300 : 'Multiple Choices',
301 : 'Moved Permanently',
302 : 'Moved Temporarily',
303 : 'See Other',
304 : 'Not Modified',
305 : 'Use Proxy',
307 : 'Temporary Redirect',
400 : 'Bad Request',
401 : 'Unauthorized',
402 : 'Payment Required',
403 : 'Forbidden',
404 : 'Not Found',
405 : 'Method Not Allowed',
406 : 'Not Acceptable',
407 : 'Proxy Authentication Required',
408 : 'Request Time-out',
409 : 'Conflict',
410 : 'Gone',
411 : 'Length Required',
412 : 'Precondition Failed',
413 : 'Request Entity Too Large',
414 : 'Request-URI Too Large',
415 : 'Unsupported Media Type',
416 : 'Requested Range Not Satisfiable',
417 : 'Expectation Failed',
418 : 'I\'m a teapot', // RFC 2324
422 : 'Unprocessable Entity', // RFC 4918
423 : 'Locked', // RFC 4918
424 : 'Failed Dependency', // RFC 4918
425 : 'Unordered Collection', // RFC 4918
426 : 'Upgrade Required', // RFC 2817
500 : 'Internal Server Error',
501 : 'Not Implemented',
502 : 'Bad Gateway',
503 : 'Service Unavailable',
504 : 'Gateway Time-out',
505 : 'HTTP Version not supported',
506 : 'Variant Also Negotiates', // RFC 2295
507 : 'Insufficient Storage', // RFC 4918
509 : 'Bandwidth Limit Exceeded',
510 : 'Not Extended' // RFC 2774
};
節(jié)選自,Nodejs源碼 ”http.js“ 143行開始。
其實從客戶端應(yīng)答結(jié)果也不難看出:
(6行):”response.end“------當(dāng)所有的響應(yīng)報頭和報文被發(fā)送完成時這個方法將信號發(fā)送給服務(wù)器。服務(wù)器會認(rèn)為這個消息完成了。
每次響應(yīng)完成之后必須調(diào)用該方法。如果指定了參數(shù) “data” ,就相當(dāng)于先調(diào)用 “response.write(data, encoding) ” 之后再調(diào)用 “response.end()” 。
(8行):”server.listen(8888)“ ------ 服務(wù)器用指定的句柄接受連接,綁定在特定的端口。
以上就是一個比較詳細(xì)的分析過程,希望有助于加深理解,代碼雖然不多,但是重在理解一些細(xì)節(jié)機制,以便日后高效的開發(fā)NodeJS應(yīng)用。
三,實例
除了可以使用"request"對象訪問請求頭數(shù)據(jù)外,還能把"request"對象當(dāng)作一個只讀數(shù)據(jù)流來訪問請求體數(shù)據(jù)。
這是一個"POST"請求的例子:
http.createServer(function (request, response) {
var body = [];
console.log(request.method) ;
console.log(request.headers) ;
request.on('data', function (chunk) {
body.push(chunk);
}) ;
request.on('end', function () {
body = Buffer.concat(body) ;
console.log(body.toString()) ;
});
}).listen(8888) ;
下是一個完整的“Http”請求數(shù)據(jù)內(nèi)容。
POST / HTTP/1.1
User-Agent: curl/7.26.0
Host: localhost
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded
Hello World
四,總結(jié)一下
(1),理解 "Http" 概念。
(2),熟練使用 "Http" 相關(guān)的api。
(3),注意細(xì)節(jié)的把控,比如:“POST,GET” 之間的處理細(xì)節(jié)。
(4),"requestListener"的理解。
(5),強調(diào)一個概念:一個http request對象是可讀流,而http response對象則是可寫流 。
相關(guān)文章
node.js學(xué)習(xí)筆記之koa框架和簡單爬蟲練習(xí)
這篇文章主要介紹了node.js學(xué)習(xí)筆記之koa框架和簡單爬蟲練習(xí),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12使用NestJS開發(fā)Node.js應(yīng)用的方法
這篇文章主要介紹了使用NestJS開發(fā)Node.js應(yīng)用的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12把Node.js程序加入服務(wù)實現(xiàn)隨機啟動
這篇文章主要介紹了把Node.js程序加入服務(wù)實現(xiàn)隨機啟動,本文使用qckwinsvc實現(xiàn)這個需求,講解了qckwinsvc的安裝和使用,需要的朋友可以參考下2015-06-06nodejs使用socket5進行代理請求的實現(xiàn)
這篇文章主要介紹了nodejs使用socket5進行代理請求的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02node中modules.exports與exports導(dǎo)出的區(qū)別
這篇文章主要介紹了node中modules.exports與exports導(dǎo)出的區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-06-06使用?Node-RED對?MQTT?數(shù)據(jù)流處理
本文將介紹使用 Node-RED 連接到 MQTT 服務(wù)器,并對 MQTT 數(shù)據(jù)進行過濾和處理后再將其發(fā)送至 MQTT 服務(wù)器的完整操作流程。讀者可以快速了解如何使用 Node-RED 對 MQTT 數(shù)據(jù)進行簡單的流處理2022-05-05Node.js的Koa實現(xiàn)JWT用戶認(rèn)證方法
本篇文章主要介紹了Node.js的Koa實現(xiàn)JWT用戶認(rèn)證方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05