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. Python小白学习之路(八)—【变量】【基本数据类型分类】【集合】【集合的功能】

    一.变量 变量的作用:记录状态的变化变量的值:描述不同的状态 二.五大基本数据类型的分类 五大基本数据类型(数字 字符串 列表 元祖 字典) 按照可变不可变来进行分类 可变:列表.字典 不可变:字符串 ...

  2. Eclipse for android 实现代码自动提示智能提示功能

    Eclipse for android 实现代码自动提示智能提示功能,介绍 Eclipse for android 编辑器中实现两种主要文件 java 与 xml 代码自动提示功能,解决 eclips ...

  3. 渐进增强与优雅降级 && css3中普通属性和前缀属性的书写顺序

     什么是渐进增强与优雅降级? 服务器和浏览器是不同的.当服务器有新版本时,开发人员直接使用新版本的服务器提供服务即可:但是浏览器端,不同的用户使用的浏览器版本不同,型号差异大,我们不可能让用户强制更新 ...

  4. 由一段代码谈前端js优化和编码规范(一) 分类: JavaScript 2015-03-21 12:43 668人阅读 评论(1) 收藏

    这段代码是撸主刚毕业那会写的,主要是实现一个左侧的导航条的折叠功能.当时实现的比较简陋,每次在导航条增加新的项目的时候,都要手动去修改js代码中写死的索引...确实是比较恼火的,后来就修改了一下,能够 ...

  5. 【C#小知识】C#中一些易混淆概念总结---------数据类型存储,方法调用,out和ref参数的使用

    这几天一直在复习C#基础知识,过程中也发现了自己以前理解不清楚和混淆的概念.现在给大家分享出来我的笔记: 一,.NET平台的重要组成部分都是有哪些 1)FCL (所谓的.NET框架类库) 这些类是微软 ...

  6. attachEvent和addEventListener区别总结

    1.attachEvent与addEventListener的区别 支持的浏览器不同.attachEvent在IE9以下的版本中受到支持.其它的都支持addEventListener. 参数不同.ad ...

  7. javascript数组原型方法

    1.javascript数组原型方法. <!DOCTYPE html> <html lang="en"> <head> <meta cha ...

  8. linux解压.tar.xz压缩包

    今天,打算更新一下node版本(v6.11.1 -> v8.9.4),结果阿里云服务器使用nvm命令下载慢如牛,于是直接在node官网找到合适的v8.9.4压缩包下载到电脑里,然后up到阿里云服 ...

  9. web前端之css快速入门

    css简介 css概述 CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中,是为了解决内容与 ...

  10. Java虚拟机(六):JVM调优工具

    工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗费性能的分析(dump文件分析)一般也不会在生产直接分析,往往dump下来的文件达1G左右,人工分析效率较低,因此利用工具来分析jvm相关问题 ...