NodeJS学习笔记之Http模块


Posted in NodeJs onJanuary 13, 2015

一,开篇分析

首先“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)以下是运行结果:

NodeJS学习笔记之Http模块 

二,细节分析实例

具体看一下这个小例子:

(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.Server或http.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行开始。

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

NodeJS学习笔记之Http模块 

(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 相关文章推荐
Ubuntu中搭建Nodejs开发环境过程分享
Jun 01 NodeJs
轻松创建nodejs服务器(2):nodejs服务器的构成分析
Dec 18 NodeJs
Jquery通过ajax请求NodeJS返回json数据实例
Nov 08 NodeJs
详解nodejs异步I/O和事件循环
Jun 07 NodeJs
nodejs中sleep功能实现暂停几秒的方法
Jul 12 NodeJs
Windows下快速搭建NodeJS本地服务器的步骤
Aug 09 NodeJs
使用nodeJs来安装less及编译less文件为css文件的方法
Nov 20 NodeJs
Nodejs连接mysql并实现增、删、改、查操作的方法详解
Jan 04 NodeJs
nodejs基于express实现文件上传的方法
Mar 19 NodeJs
nodejs中实现修改用户路由功能
May 24 NodeJs
独立部署小程序基于nodejs的服务器过程详解
Jun 24 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 NodeJs
Nodejs学习笔记之Stream模块
Jan 13 #NodeJs
Nodejs学习笔记之NET模块
Jan 13 #NodeJs
Nodejs学习笔记之Global Objects全局对象
Jan 13 #NodeJs
Nodejs为什么选择javascript为载体语言
Jan 13 #NodeJs
NodeJS中Buffer模块详解
Jan 07 #NodeJs
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
Jan 01 #NodeJs
Nodejs中调用系统命令、Shell脚本和Python脚本的方法和实例
Jan 01 #NodeJs
You might like
第四节--构造函数和析构函数
2006/11/16 PHP
Laravel创建数据库表结构的例子
2019/10/09 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
2019/10/22 PHP
php模拟实现斗地主发牌
2020/04/22 PHP
javascript与css3动画结合使用小结
2015/03/11 Javascript
jQuery获取页面元素绝对与相对位置的方法
2015/06/10 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
JavaScript数组实现数据结构中的队列与堆栈
2016/05/26 Javascript
ECMAScript6轮播图实践知识总结
2016/08/17 Javascript
webpack学习笔记之代码分割和按需加载的实例详解
2017/07/20 Javascript
微信小程序之选项卡的实现方法
2017/09/29 Javascript
mint-ui的search组件在键盘显示搜索按钮的实现方法
2017/10/27 Javascript
vue select二级联动第二级默认选中第一个option值的实例
2018/01/10 Javascript
[50:04]DOTA2上海特级锦标赛D组小组赛#2 Liquid VS VP第二局
2016/02/28 DOTA
python str与repr的区别
2013/03/23 Python
对python中raw_input()和input()的用法详解
2018/04/22 Python
用Python写脚本,实现完全备份和增量备份的示例
2018/04/29 Python
详解python如何在django中为用户模型添加自定义权限
2018/10/15 Python
Python3 安装PyQt5及exe打包图文教程
2019/01/08 Python
Django models filter筛选条件详解
2020/03/16 Python
Python selenium环境搭建实现过程解析
2020/09/08 Python
Holiday Inn中国官网:IHG旗下假日酒店预订
2018/04/08 全球购物
计算机通信专业推荐信
2014/02/22 职场文书
车间机修工岗位职责
2014/02/28 职场文书
海飞丝广告词
2014/03/20 职场文书
机电专业毕业生求职信
2014/07/01 职场文书
党员学习党的群众路线思想汇报(5篇)
2014/09/10 职场文书
总经理检讨书
2014/09/15 职场文书
2014预备党员批评与自我批评思想汇报
2014/09/20 职场文书
深入开展党的群众路线教育实践活动心得体会
2014/11/05 职场文书
预备党员转正材料
2014/12/19 职场文书
市场部岗位职责
2015/02/12 职场文书
2016优秀员工先进事迹材料
2016/02/25 职场文书
共青团优秀团员申请书(范文)
2019/08/15 职场文书
MySQL 数据库范式化设计理论
2022/04/22 MySQL
人工智能深度学习OpenAI baselines的使用方法
2022/05/20 Python