nodejs事件机制
http服务器和客户端

node.js标准库提供了http模块,其中封装了一个高效的http服务器和一个简易的http客户端

HTTP服务器

1. http.createServer()创建HTTP服务器。

//服务器实例
var httpServer = require("http")
httpServer.createServer(function(req,res){
res.writeHead(200,{"Content-Type":"text/html"});
res.write("<h2>hello world</h2>");
res.end("<h3>你好</h3>");
}).listen(2333);
console.log("http server is listening at port 2333,localhost:2333");

将一个函数作为HTTP请求处理函数,这个函数接受两个参数,分别是请求对象(req)和响应对象(res),在函数体内,res显式的写回了响应代码200(表示请求成功),指定响应头为"Content-Type":"text/html",然后写入响应体通过res.end()结束并发送,最后调用listen函数,启动服务器并且监听2333端口。

  • 运行之后,我们在浏览器打开localhost:2333,就能简单的访问我们实现的接口了
  • 点击Network,我们看到了我们平时调用的接口,和返回的数据。

通过http.createServer方法创建HTTP服务器后,就可以使用http的服务端功能。node的HTTP服务端,主要涉及http.server,http.serverResponse,http.IncomingMessage三个对象。

2. http.Server

http.server是一个基于事件的http服务器,所有的请求都被封装为独立的事件,开发者只需要对他的事件编写响应函数即可实现HTTP服务器的所有功能,它继承自EventEmitter,他的核心由Node.js下层的C++部分实现,而接口由JavaScript封装,兼顾了性能和简易性,

为了处理客户端请求,需要在服务端监听来自客户的'request'事件,'request'事件的回调函数中,会返回一个http.IncomingMessage实例和一个http.ServerResponse。

  • connection: 当TCP链接建立时,该事件被触发,提供一个参数socket,为net.Socket的实例,connection事件的粒度要大于request,因为客户端在keep-Alive模式下可能在同一个链接内发送多次请求(相对于createserver,可以进行前后端实时通信)
wsServer.on('connection',function(sock){
sock.on('a',function(num1,num2){
console.log(`接到了浏览器发送的数据:${num1}`)
})
setInterval(function(){
sock.emit('ttt',Math.random())
},500)
})
  • close: 当服务器关闭时,该事件被触发,注意不是在用户连接断开时,等等事件
  • request: 每次接收到一个请求时触发。

var server = new http.Server();
server.on("request", function (req, res) {
res.writeHead(200, { "Content-Type": "text/html" });
res.write("<h2>node.js</h2>");
res.end("<h3>test</h3>");
}).listen(2333);
console.log("http server is listening at port 2333:2333");

req 是一个http.IncomingMessage实例

res 是一个http.ServerResponse实例

3. http.ServerResponse 响应 res

http.ServerResponse是返回给客户端的信息,决定了用户最终能看到的结果,它也是由http.Server的request事件发送的,作为第二个参数传递,一般简称response或者res。

http.ServerResponse有三个重要的成员函数,用于返回响应头,响应内容以及结束请求:

(1)response.writeHead(statsCode,[headers]):向请求的客户端发送响应头,statusCode是HTTP状态码如200(请求成功),404(未找到)等,headers是一个类似关联数组的对象,表示响应头的每个属性,该函数在请求内最多只能调用一次,如果不调用,则会自动生成一个响应头。

(2)response.write(data,[encoding]):向请求的客户端发送响应内容,data是一个buffer或者字符串,表示要发送的内容,如果data是字符串,那么需要指定encoding编码方式,默认是utf-8,在response.end之前调用,response.write可以被调用多次;

(3)response.end([data],[encoding]):结束响应,告知客户端所有发送已经完成,当所有要返回的内容发送完毕的时候,该函数必须调用一次,他可接受两个参数,意义和response.write相同,如果不调用该函数,客户端将永远处于等待状态;

4. http.IncomingMessage 请求 req

HTTP客户端

http提供了两个函数http.request和http.get,作为客户端向HTTP服务器发起请求;

1. http.request(options[, callback])

http.request则是一个http客户端工具,用于向http服务发起请求;

const postData = querystring.stringify({
'msg' : 'Hello World!'
}); const options = {
hostname: 'www.google.com',
port: 80,
path: '/upload',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
}; const req = http.request(options, (res) => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应头: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`响应主体: ${chunk}`);
});
res.on('end', () => {
console.log('响应中已无数据。');
});
}); req.on('error', (e) => {
console.error(`请求遇到问题: ${e.message}`);
}); // 写入数据到请求主体
req.write(postData);
req.end();

注意,在例子中调用了 req.end()。 使用 http.request() 必须总是调用 req.end() 来表明请求的结束,即使没有数据被写入请求主体。

如果请求过程中遇到任何错误(DNS 解析错误、TCP 级的错误、或实际的 HTTP 解析错误),则在返回的请求对象中会触发 'error' 事件。 对于所有的 'error' 事件,如果没有注册监听器,则抛出错误。

以下是需要注意的几个特殊的请求头。

  • 发送 'Connection: keep-alive' 会通知 Node.js,服务器的连接应一直持续到下一个请求。

  • 发送 'Content-Length' 请求头会禁用默认的块编码。

  • 发送 'Expect' 请求头会立即发送请求头。 通常情况下,当发送 'Expect: 100-continue' 时,超时时间与 continue 事件的监听器都需要被设置。 详见 RFC2616 章节 8.2.3。

  • 发送 Authorization 请求头会替代 auth 选项计算基本身份验证。

2. http.get(options[, callback])

该对象在HTTP服务器内部被创建。作为第二个参数呗传入'request'事件

  • 接收与http.request()相同的设置。 method一直设置为GET,忽略继承自原型的属性

  • 返回: <http.ClientRequest>

http.get('http://nodejs.org/dist/index.json', (res) => {
const { statusCode } = res;
const contentType = res.headers['content-type']; let error;
if (statusCode !== 200) {
error = new Error('请求失败。\n' +
`状态码: ${statusCode}`);
} else if (!/^application\/json/.test(contentType)) {
error = new Error('无效的 content-type.\n' +
`期望 application/json 但获取的是 ${contentType}`);
}
if (error) {
console.error(error.message);
// 消耗响应数据以释放内存
res.resume();
return;
} res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => { rawData += chunk; });
res.on('end', () => {
try {
const parsedData = JSON.parse(rawData);
console.log(parsedData);
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`错误: ${e.message}`);
});

3. http.ClientRequest

该对象在http.request()内部被创建并返回。它表示着一个正则处理的请求,其请求头已进入队列。请求头仍可使用 setHeader(name, value)、getHeader(name) 和 removeHeader(name) 进行修改。实际的请求头会与第一个数据块一起发送或当调用request.end()时发送。

  • connect事件
const http = require('http');
const net = require('net');
const url = require('url'); // 创建一个 HTTP 代理服务器
const proxy = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('okay');
});
proxy.on('connect', (req, cltSocket, head) => {
// 连接到一个服务器
const srvUrl = url.parse(`http://${req.url}`);
const srvSocket = net.connect(srvUrl.port, srvUrl.hostname, () => {
cltSocket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node.js-Proxy\r\n' +
'\r\n');
srvSocket.write(head);
srvSocket.pipe(cltSocket);
cltSocket.pipe(srvSocket);
});
}); // 代理服务器正在运行
proxy.listen(1337, '127.0.0.1', () => { // 发送一个请求到代理服务器
const options = {
port: 1337,
hostname: '127.0.0.1',
method: 'CONNECT',
path: 'www.google.com:80'
}; const req = http.request(options);
req.end(); req.on('connect', (res, socket, head) => {
console.log('已连接!'); // 通过代理服务器发送一个请求
socket.write('GET / HTTP/1.1\r\n' +
'Host: www.google.com:80\r\n' +
'Connection: close\r\n' +
'\r\n');
socket.on('data', (chunk) => {
console.log(chunk.toString());
});
socket.on('end', () => {
proxy.close();
});
});
});

4. http.Agent

负责为HTTP客户端管理连接的持续与复用。它为一个给定的主机和端口维护着一个等待请求的队列,且为每个请求重复使用一个单一的socket连接直到队列为空,此时socket会呗销毁到一个连接池中等待被有着相同主机与端口的请求再次使用。 是否被销毁或被放入连接池取决于 keepAlive 选项。

http.get(options, (res) => {
// 处理事情
}).on('socket', (socket) => {
socket.emit('agentRemove');
});

当 socket 触发 'close' 事件或 'agentRemove' 事件时,它会被移出代理。 当打算长时间保持打开一个 HTTP 请求且不想它留在代理中,则可以如上处理

【node】node的核心模块---http模块,http的服务器和客户端的更多相关文章

  1. Node.js权威指南 (8) - 创建HTTP与HTTPS服务器及客户端

    8.1 HTTP服务器 / 177 8.1.1 创建HTTP服务器 / 177 8.1.2 获取客户端请求信息 / 182 8.1.3 转换URL字符串与查询字符串 / 184 8.1.4 发送服务器 ...

  2. Node.js 手册查询-1-核心模块方法

    Node.js 学习手册 标签(空格分隔): node.js 模块 核心模块 核心模块是被编译成二进制代码,引用的时候只需require表示符即可 os 系统基本信息 os模块可提供操作系统的一些基本 ...

  3. 《深入浅出Node.js》第2章 模块机制

    @by Ruth92(转载请注明出处) 第2章 模块机制 JavaScript 先天缺乏的功能:模块. 一.CommonJS 规范: JavaScript 规范的缺陷:1)没有模块系统:2)标准库较少 ...

  4. node基础(二)_模块以及处理乱码问题

    一.前言 本次内容主要包括: 1.node.js中的模块系统 2.解决上篇中服务器响应的汉字乱码问题 二.知识 1.node中的模块   分为三种: 核心模块(node定义的如前面用到的fs,http ...

  5. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

  6. Node.js进程管理之Process模块

    在前面Node.js事件运行机制也有提到,Node.js应用在单个线程运行,但是现在大部分服务器都是多处理器,为了方便使用多个进程,Node.js提供了3个模块.Process模块提供了访问正在运行的 ...

  7. node项目中用到的一些模块

    1.http模块,用来搭建服务器 代码,简单服务器实现 var http = require('http'); http.createServer(function (request, respons ...

  8. node(03)--利用 HTTP 模块 URl 模块 PATH 模块 FS 模块创建一个 WEB 服务器

    Web 服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,可以向浏览器等 Web 客户端提供文档,也可以放置网站文件,让全世界浏览:可以放置数据文件,让全世界下载.目前最主流的三个 We ...

  9. node.js中使用http模块创建服务器和客户端

    node.js中的 http 模块提供了创建服务器和客户端的方法,http 全称是超文本传输协议,基于 tcp 之上,属于应用层协议. 一.创建http服务器 const http = require ...

随机推荐

  1. jq02--基础函数

    jq是一个js函数库,主要是为事件处理特别设计的,现在我们继续学习一些jq函数. 1.jq效果: 显示与隐藏: $().hide(speed,callback) speed--"slow&q ...

  2. sublime text3 --前端工程师必备

    sublime text3 --前端工程师必备神器 导读目录: 下载与Emmet插件安装 sublime text3 中cssrem安装与使用 sublime Text 3的中文文件名显示为方框的问题 ...

  3. Linq基础知识小记一

    1.LINQ(语言级集成查询)的作用就是提供一种统一且对称的方式,让程序员在广义的数据上获取和操作数据.广义的数据包括XML文档数据.元数据.System.Data.dll和System.Data.S ...

  4. C# 对象相等性判断和同一性判断

    在日常开发中经常需要编写代码比较不同的对象.例如,有时需要将对象都放到一个集合中,并编写代码对集合中的对象进行排序.搜索或者比较. System.Object类有两个Equals方法,如下: 1.实例 ...

  5. Apache版本hadoop-2.6.0.tar.gz平台下搭建Hue

    不多说,直接上干货! http://archive.apache.org/dist/ http://www.cnblogs.com/smartloli/p/4527168.html http://ww ...

  6. win10上走网络打印机(不需找驱动包,会自动)

    不多说,直接上干货! 之前是 现在是 结束 欢迎大家,加入我的微信公众号:大数据躺过的坑        人工智能躺过的坑       同时,大家可以关注我的个人博客:    http://www.cn ...

  7. zabbix邮件内容乱码与邮件内容为附件解决办法

    在zabbix的实际使用过程中,在收到邮件预警的时候,我们会发现邮件内容是乱码的,在手机端收到的是附件,而且附件下载后的文件类型是打不开的.这样我们不知道我们是哪个服务器的哪项服务出了问题,接下来我们 ...

  8. Go 开发

    0.参数传递永远是值传递,地址也是一种值 1.go 开发环境的配置 2.import 包的几种形式: 1)_,默认导入一个包时,会将包中内容导入再执行包中的init()方法,有时并不需要某个包,只是想 ...

  9. Linux-(tar,gzip,df,du)

    tar命令 首先要弄清两个概念:打包和压缩.打包是指将一大堆文件或目录变成一个总的文件:压缩则是将一个大的文件通过一些压缩算法变成一个小文件. 为什么要区分这两个概念呢?这源于Linux中很多压缩程序 ...

  10. WPF 进程间传递参数

    WPF 进程间传递参数          在软件开发中有时需要在一个软件中启动另一个软件,这时用Process.Start(“软件路径”)可以启动另一个软件.如果在这个过程中还需要传递一些参数给新启动 ...