NodeJS學(xué)習(xí)筆記之Http模塊
一,開(kāi)篇分析
首先“Http”這個(gè)概念大家應(yīng)該比較熟悉了,它不是基于特定語(yǔ)言的,是一個(gè)通用的應(yīng)用層協(xié)議,不同語(yǔ)言有不同的實(shí)現(xiàn)細(xì)節(jié),但是萬(wàn)變不離其宗,思想是相同的,
NodeJS作為一個(gè)宿主運(yùn)行環(huán)境,以JavaScript為宿主語(yǔ)言,它也有自己實(shí)現(xiàn)的一套標(biāo)準(zhǔn),這篇文章我們就一起來(lái)學(xué)習(xí)一下 “Http模塊” 。但是作為前提來(lái)說(shuō),
希望大家可以先閱讀一下官網(wǎng)提供的api,有一個(gè)前置了解,這樣就方便多了,以下是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
讓我們先從一個(gè)簡(jiǎn)單例子開(kāi)始,創(chuàng)建一個(gè)叫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)以下是運(yùn)行結(jié)果:
二,細(xì)節(jié)分析實(shí)例
具體看一下這個(gè)小例子:
(1行):通過(guò)"require"引入NodeJS自帶的"http"模塊,并且把它賦值給http變量。
(2行):調(diào)用http模塊提供的函數(shù):"createServer" 。這個(gè)函數(shù)會(huì)返回一個(gè)新的web服務(wù)器對(duì)象。
參數(shù) "requestListener" 是一個(gè)函數(shù),它將會(huì)自動(dòng)加入到 "request" 事件的監(jiān)聽(tīng)隊(duì)列。
當(dāng)一個(gè)request到來(lái)時(shí),Event-Loop會(huì)將這個(gè)Listener回調(diào)函數(shù)放入執(zhí)行隊(duì)列, node中所有的代碼都是一個(gè)一個(gè)從執(zhí)行隊(duì)列中拿出來(lái)執(zhí)行的。
這些執(zhí)行都是在工作線程上(Event Loop本身可以認(rèn)為在一個(gè)獨(dú)立的線程中,我們一般不提這個(gè)線程,而將node稱呼為一個(gè)單線程的執(zhí)行環(huán)境),
所有的回調(diào)都是在一個(gè)工作線程上運(yùn)行。
我們?cè)谠賮?lái)看一下"requestListener"這個(gè)回調(diào)函數(shù),它提供了兩個(gè)參數(shù)(request,response),
每次收到一個(gè)請(qǐng)求時(shí)觸發(fā)。注意每個(gè)連接又可能有多個(gè)請(qǐng)求(在keep-alive的連接中)。
"request"是http.IncomingMessage的一個(gè)實(shí)例。"response"是http.ServerResponse的一個(gè)實(shí)例。
一個(gè)http request對(duì)象是可讀流,而http response對(duì)象則是可寫流。
一個(gè)"IncomingMessage"對(duì)象是由http.Server或http.ClientRequest創(chuàng)建的,
并作為第一參數(shù)分別傳遞給"request"和"response"事件。
它也可以被用來(lái)訪問(wèn)應(yīng)答的狀態(tài),頭文件和數(shù)據(jù)。
它實(shí)現(xiàn)了 "Stream" 接口以及以下額外的事件,方法和屬性。(具體參考api)。
(3行):“writeHeader”,使用 "response.writeHead()" 函數(shù)發(fā)送一個(gè)Http狀態(tài)200和Http頭的內(nèi)容類型(content-type)。
向請(qǐng)求回復(fù)響應(yīng)頭。"statusCode"是一個(gè)三位是的HTTP狀態(tài)碼,例如 404 。最后一個(gè)參數(shù),"headers",是響應(yīng)頭的內(nèi)容。
舉個(gè)栗子:
var body = 'hello world' ;
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
}) ;
注意:Content-Length 是以字節(jié)(byte)計(jì)算,而不是以字符(character)計(jì)算。
之前的例子原因是字符串 “Hello World !” 只包含了單字節(jié)的字符。
如果body包含了多字節(jié)編碼的字符,就應(yīng)當(dāng)使用Buffer.byteLength()來(lái)確定在多字節(jié)字符編碼情況下字符串的字節(jié)數(shù)。
需要進(jìn)一步說(shuō)明的是Node不檢查Content-Lenth屬性和已傳輸?shù)腷ody長(zhǎng)度是否吻合。
statusCode是一個(gè)三位是的HTTP狀態(tài)碼, 例如:"404" 。這里要說(shuō)的是 "http.STATUS_CODES" ,全部標(biāo)準(zhǔn)"Http"響應(yīng)狀態(tài)碼的集合和簡(jiǎn)短描述都在里面。
如下是源碼參考:
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行開(kāi)始。
其實(shí)從客戶端應(yīng)答結(jié)果也不難看出:
(6行):”response.end“------當(dāng)所有的響應(yīng)報(bào)頭和報(bào)文被發(fā)送完成時(shí)這個(gè)方法將信號(hào)發(fā)送給服務(wù)器。服務(wù)器會(huì)認(rèn)為這個(gè)消息完成了。
每次響應(yīng)完成之后必須調(diào)用該方法。如果指定了參數(shù) “data” ,就相當(dāng)于先調(diào)用 “response.write(data, encoding) ” 之后再調(diào)用 “response.end()” 。
(8行):”server.listen(8888)“ ------ 服務(wù)器用指定的句柄接受連接,綁定在特定的端口。
以上就是一個(gè)比較詳細(xì)的分析過(guò)程,希望有助于加深理解,代碼雖然不多,但是重在理解一些細(xì)節(jié)機(jī)制,以便日后高效的開(kāi)發(fā)NodeJS應(yīng)用。
三,實(shí)例
除了可以使用"request"對(duì)象訪問(wèn)請(qǐng)求頭數(shù)據(jù)外,還能把"request"對(duì)象當(dāng)作一個(gè)只讀數(shù)據(jù)流來(lái)訪問(wèn)請(qǐng)求體數(shù)據(jù)。
這是一個(gè)"POST"請(qǐng)求的例子:
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) ;
下是一個(gè)完整的“Http”請(qǐng)求數(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),強(qiáng)調(diào)一個(gè)概念:一個(gè)http request對(duì)象是可讀流,而http response對(duì)象則是可寫流 。
相關(guān)文章
node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲練習(xí)
這篇文章主要介紹了node.js學(xué)習(xí)筆記之koa框架和簡(jiǎn)單爬蟲練習(xí),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12node.js中的fs.truncate方法使用說(shuō)明
這篇文章主要介紹了node.js中的fs.truncate方法使用說(shuō)明,本文介紹了fs.truncate的方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12使用NestJS開(kāi)發(fā)Node.js應(yīng)用的方法
這篇文章主要介紹了使用NestJS開(kāi)發(fā)Node.js應(yīng)用的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12nodejs實(shí)現(xiàn)bigpipe異步加載頁(yè)面方案
本文給大家分享的是使用nodejs結(jié)合bigpipe實(shí)現(xiàn)異步加載頁(yè)面的方案,非常的實(shí)用,也是以后前端性能優(yōu)化的一個(gè)方向,希望大家能夠喜歡。2016-01-01實(shí)時(shí)通信WebSocket的原理和工作過(guò)程
WebSocket持久連接使得服務(wù)器可以主動(dòng)向客戶端推送數(shù)據(jù),而不需要等待客戶端的請(qǐng)求,是一種專門設(shè)計(jì)用于實(shí)現(xiàn)持久連接的協(xié)議,WebSocket的持久連接特性使其成為實(shí)時(shí)性要求高的應(yīng)用的理想選擇,如在線聊天、實(shí)時(shí)游戲、數(shù)據(jù)監(jiān)控等2023-12-12把Node.js程序加入服務(wù)實(shí)現(xiàn)隨機(jī)啟動(dòng)
這篇文章主要介紹了把Node.js程序加入服務(wù)實(shí)現(xiàn)隨機(jī)啟動(dòng),本文使用qckwinsvc實(shí)現(xiàn)這個(gè)需求,講解了qckwinsvc的安裝和使用,需要的朋友可以參考下2015-06-06nodejs使用socket5進(jìn)行代理請(qǐng)求的實(shí)現(xiàn)
這篇文章主要介紹了nodejs使用socket5進(jìn)行代理請(qǐng)求的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02node中modules.exports與exports導(dǎo)出的區(qū)別
這篇文章主要介紹了node中modules.exports與exports導(dǎo)出的區(qū)別,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06使用?Node-RED對(duì)?MQTT?數(shù)據(jù)流處理
本文將介紹使用 Node-RED 連接到 MQTT 服務(wù)器,并對(duì) MQTT 數(shù)據(jù)進(jìn)行過(guò)濾和處理后再將其發(fā)送至 MQTT 服務(wù)器的完整操作流程。讀者可以快速了解如何使用 Node-RED 對(duì) MQTT 數(shù)據(jù)進(jìn)行簡(jiǎn)單的流處理2022-05-05Node.js的Koa實(shí)現(xiàn)JWT用戶認(rèn)證方法
本篇文章主要介紹了Node.js的Koa實(shí)現(xiàn)JWT用戶認(rèn)證方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05