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. Java并发(一)-了解线程安全

    线程不安全性 先来举例说明线程不安全是什么情况下发生的:例如一个变量可以被多个线程进行访问,那么在大量线程并发访问这个变量的情况下,线程执行的顺序会给最后的结果带来不可预估的错误. 先定义一个单例类S ...

  2. 【NOIP2018】保卫王国 动态dp

    此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...

  3. Inno Setup入门(二十三)——Inno Setup类参考(9)

    今天就简单说一下ProgressBar. TNewProgressBar = class(TWinControl)   property Min: Longint; read write;   pro ...

  4. XmlDocument 避免XXE

    string xml2 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\&quo ...

  5. 数据?算法-> which is important?

    谷歌的强不是强在 PageRank 算法,而在于它是第一个在排名时把链接——而不只是文字和标题——考虑进去的.又以自己教的数据挖掘课为例.他让学生以 Netflix 用户对一万八千多部电影的打分为基础 ...

  6. Spring Security构建Rest服务-0702-个性化用户认证流程2

    登录成功后的处理AuthenticationSuccessHandler: 认证成功后,默认情况下spring security会继续访问之前访问的url,如果想自定义处理逻辑,用默认的就不行了.此时 ...

  7. linux 下screen 使用

    screen命令的常规用法: screen -d -r:连接一个screen进程,如果该进程是attached,就先踢掉远端用户再连接. screen -D -r:连接一个screen进程,如果该进程 ...

  8. unity 图片变纯色填充

    unity自带shader 即可

  9. mybatis异常:Error instantiating class com.psc.bean.User with invalid types () or values ().

    Error instantiating class com.psc.bean.User with invalid types () or values (). 是由于bean类没有无参构建方法,添加一 ...

  10. centos中软件源码简单的编译安装./configure,make ,make install

    参考 Linux下源码编译安装详解 源码编译安装分三个步骤 1. 编译参数配置 2. 编译 3. 安装 1. 源码编译安装环境检查以及编译参数配置 编译器在开始工作之前,需要知道当前的系统环境,比如标 ...