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. pythonweb框架Flask学习笔记03-变量规则

    #-*- coding:utf-8 -*- from flask import Flask app=Flask(__name__) @app.route('/post/<int:postid&g ...

  2. iOS-Button图片和文字垂直居中【按钮图片和文字同时居中】

    以前不怎么有这样的需求,最近开发经常用到,所以就干脆封装一个这样的 Button 让图片和字体都垂直居中,重写layoutSubviews方法,来实现就可以,至于 layoutSubviews 方法什 ...

  3. 【GDKOI2016】 魔卡少女 线段树

    题目大意:给你一个长度为n的序列${a_1....a_n}$,有$m$次操作 每次操作有两种情况:修改$a_i$的值,询问$[l,r]$中所有子区间的异或和. 数据范围:$n,m≤10^5$,$a_i ...

  4. QuantLib 金融计算——基本组件之 Currency 类

    目录 QuantLib 金融计算--基本组件之 Currency 类 概述 构造函数 成员函数 如果未做特别说明,文中的程序都是 python3 代码. QuantLib 金融计算--基本组件之 Cu ...

  5. 02--STL算法(函数对象和谓词)

    一:函数对象(仿函数):实现状态记录等其他操作<相对于普通函数> 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象. 即是重载了“ ...

  6. Mac 10.12允许任何来源

    sudo spctl --master-disable 然后即可设置.

  7. java android中日期时间 问题总结

    Date 类型: Date date = new Date();   // 代表获取当前系统日期和时间 System.out.println(date); 使用类的方法设置时间和日期:(通过该方法初始 ...

  8. python——利用selenium模仿键盘输入跳转

    这是我以前遇到的一个网站:人卫临床助手,这个网站比较奇怪,不能点击右键查看源码,但是大家可以使用ctrl+U,打开开发者选项,点击network,然后点击第2页和第3页: 可以看到上面的URL是一模一 ...

  9. Filter应用之-验证用户是否已经登录

    过滤器: public class LoginFilter implements Filter{ @Override public void init(FilterConfig filterConfi ...

  10. Docker挂载主机目录Docker访问出现Permission denied的解决办法

    Docker挂载主机目录,访问相应的文件出现Premission denied的权限访问问题,   [root@localhost soft]# docker images REPOSITORY    ...