一,开篇分析

首先“Http”这个概念大家应该比较熟悉了,它不是基于特定语言的,是一个通用的应用层协议,不同语言有不同的实现细节,但是万变不离其宗,思想是相同的,

NodeJS作为一个宿主运行环境,以JavaScript为宿主语言,它也有自己实现的一套标准,这篇文章我们就一起来学习一下 “Http模块” 。但是作为前提来说,

希望大家可以先阅读一下官网提供的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

让我们先从一个简单例子开始,创建一个叫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)以下是运行结果:

 

二,细节分析实例

具体看一下这个小例子:

(1行):通过"require"引入NodeJS自带的"http"模块,并且把它赋值给http变量。

(2行):调用http模块提供的函数:"createServer" 。这个函数会返回一个新的web服务器对象。

  参数 "requestListener" 是一个函数,它将会自动加入到 "request" 事件的监听队列。

  当一个request到来时,Event-Loop会将这个Listener回调函数放入执行队列, node中所有的代码都是一个一个从执行队列中拿出来执行的。

  这些执行都是在工作线程上(Event Loop本身可以认为在一个独立的线程中,我们一般不提这个线程,而将node称呼为一个单线程的执行环境),

  所有的回调都是在一个工作线程上运行。

  我们在再来看一下"requestListener"这个回调函数,它提供了两个参数(request,response),

  每次收到一个请求时触发。注意每个连接又可能有多个请求(在keep-alive的连接中)。

  "request"http.IncomingMessage的一个实例。"response"http.ServerResponse的一个实例。

  一个http request对象是可读流,而http response对象则是可写流。

  一个"IncomingMessage"对象是由http.Serverhttp.ClientRequest创建的,

  并作为第一参数分别传递给"request""response"事件。

  它也可以被用来访问应答的状态,头文件和数据。

  它实现了 "Stream" 接口以及以下额外的事件,方法和属性。(具体参考api)。

(3行):“writeHeader”,使用 "response.writeHead()"  函数发送一个Http状态200和Http头的内容类型(content-type)。

  向请求回复响应头。"statusCode"是一个三位是的HTTP状态码,例如 404 。最后一个参数,"headers",是响应头的内容。

  举个栗子:

 var body = 'hello world' ;
response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
}) ;

 注意:Content-Length 是以字节(byte)计算,而不是以字符(character)计算

  之前的例子原因是字符串 “Hello World !” 只包含了单字节的字符。

  如果body包含了多字节编码的字符,就应当使用Buffer.byteLength()来确定在多字节字符编码情况下字符串的字节数。

  需要进一步说明的是Node不检查Content-Lenth属性和已传输的body长度是否吻合。

 statusCode是一个三位是的HTTP状态码, 例如:"404" 。这里要说的是 "http.STATUS_CODES" ,全部标准"Http"响应状态码的集合和简短描述都在里面。

 如下是源码参考:

  

 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
};

节选自,Nodejs源码 ”http.js“ 143行开始。

其实从客户端应答结果也不难看出:

(6行):”response.end“------当所有的响应报头和报文被发送完成时这个方法将信号发送给服务器。服务器会认为这个消息完成了。

  每次响应完成之后必须调用该方法。如果指定了参数 “data” ,就相当于先调用  “response.write(data, encoding) ” 之后再调用 “response.end()” 。

(8行):”server.listen(8888)“ ------ 服务器用指定的句柄接受连接,绑定在特定的端口。

以上就是一个比较详细的分析过程,希望有助于加深理解,代码虽然不多,但是重在理解一些细节机制,以便日后高效的开发NodeJS应用。

三,实例赏心

除了可以使用"request"对象访问请求头数据外,还能把"request"对象当作一个只读数据流来访问请求体数据。

这是一个"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”请求数据内容。

 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

四,总结一下

(1),理解 "Http" 概念。

(2),熟练使用 "Http" 相关的api。

(3),注意细节的把控,比如:“POST,GET” 之间的处理细节。

(4),"requestListener"的理解。

(5),强调一个概念:一个http request对象是可读流,而http response对象则是可写流 。

                 哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼……(*^__^*)             

大熊君大话NodeJS之------Http模块的更多相关文章

  1. 大熊君大话NodeJS之------Net模块

    一,开篇分析 从今天开始,我们来深入具体的模块学习,这篇文章是这个系列(大熊君大话NodeJS)文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中, 对NodeJS也有一个基本的认识,没事 ...

  2. 大熊君大话NodeJS之------Stream模块

    一,开篇分析 流是一个抽象接口,被 Node 中的很多对象所实现.比如对一个 HTTP 服务器的请求是一个流,stdout 也是一个流.流是可读,可写或兼具两者的. 最早接触Stream是从早期的un ...

  3. 大熊君大话NodeJS之------MongoDB模块(额外篇)

    一,开篇分析 这篇属于扩展知识篇,因为在下面的文章中会用到数据库操作,所以今天就来说说它(Mongodb模块). (1),简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为 ...

  4. 大熊君大话NodeJS之------Buffer模块

    一,开篇分析 所谓缓冲区Buffer,就是 "临时存贮区" 的意思,是暂时存放输入输出数据的一段内存. JS语言自身只有字符串数据类型,没有二进制数据类型,因此NodeJS提供了一 ...

  5. 大熊君大话NodeJS之------Connect中间件模块(第一季)

    一,开篇分析 截止到今天来说,NodeJS系列文章已经有将近十篇了,让我们回顾一下: (1),大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底) (2),大 ...

  6. 大熊君大话NodeJS之------基于Connect中间件的小应用(Bigbear记事本应用之第一篇)

    一,开篇分析 大家好哦,大熊君又来了,昨天因为有点个人的事没有写博客,今天又出来了一篇,这篇主要是写一个记事本的小应用,前面的文章, 我也介绍过“Connect”中间件的使用以及“Mongodb”的用 ...

  7. 大熊君大话NodeJS之开篇------Why NodeJS(将Javascript进行到底)

    一,开篇分析 大家好啊,大熊君又来啦(*^__^*) 嘻嘻……,之前我写过一系列关于JS(OOP与设计模式)方面的文章,反响还好,其实这也是对我本人最大的鼓励,于是我决定我要将JavaScript进行 ...

  8. 大熊君大话NodeJS之 ------ Connect中间件第二季(源码分析)

    一,开篇分析 大家好,大熊君又回来了,今天这篇文章主要是对"Connect"中间件以及相关辅助中间件,做一个源码分析系列,我想上一篇文章大家也看了, 介绍了使用方式及用途,而这篇也 ...

  9. 大熊君大话NodeJS之------FS文件模块

    一,开篇分析 文件系统模块是一个简单包装的标准 POSIX 文件 I/O 操作方法集.可以通过调用 require("fs") 来获取该模块.文件系统模块中的所有方法均有异步和同步 ...

随机推荐

  1. Teamviewer11现在无法捕捉屏幕画面。这可能是由于快速的用户切换或远程桌面会话断开/最小化。

    如果你用“远程桌面”连过去开启Teamviewer的话,当你退出“远程桌面”后,外网用Teamviewer连接就会出现这个问题. 解决方法: 不用远程连接过去开启Teamviewer,直接在在电脑本机 ...

  2. 一个关于AdaBoost算法的简单证明

    下载本文PDF格式(Academia.edu) 本文给出了机器学习中AdaBoost算法的一个简单初等证明,需要使用的数学工具为微积分-1. Adaboost is a powerful algori ...

  3. django redis操作

    from utils.redis.connect import redis_cache as rr.flushdb() 列表操作 r.lpush("name", xxxx) or ...

  4. 获取URL列表,设置代理请求URL,https的加密方式处理

    做了一个测试的一个小工具,需求如下: 1.有一批URL列表,需要知道哪个URL请求响应内容中包含http:关键字的. 2.url请求包括http和https 2种协议 3.要部署在linux服务器上, ...

  5. CloseHandle(IntPtr handle)抛异常

    [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static ext ...

  6. 【Alpha阶段】第五次Scrum例会

    由于软工整个项目规划延期1周,我们将停止2天的Scrum,进行相应的修整 会议信息 时间:2016.10.21 22:30 时长:20min 地点:大运村1号公寓5楼楼道 类型:日常Scrum会议 个 ...

  7. Linux学习一周初体验

    Linux一周初体验一.准备工欲善其事,必先利其器--虚拟机+Redhat7.0构成学习的环境.安装有条不紊.按部就班.......(涉及到的KVM.VNC.Root密码重置等内容,之后再详细了解)注 ...

  8. 在Android上实现使用Facebook登录(基于Facebook SDK 3.5)

    准备工作: 1.       Facebook帐号,国内开发者需要一个vpn帐号(网页可以浏览,手机可以访问) 2.       使用Facebook的SDK做应用需要一个Key Hashes值. 2 ...

  9. centos'的yum安装php的memcache扩展

    centos'的yum安装php的memcache扩展 博客分类: linux   让php能使用memcached服务的扩展有两种:memcache 和 memcached 1. 先安装libmem ...

  10. Spring MVC学习笔记——注解式控制器