Node.js中的Http模块、http协议、http缓存机制、三次握手四次挥手

目录

1 Http模块

1.1 httphttp.METHODS

http.createServer(options[, requestListener]

 http.request(options[, callback])

1.2 http.Server

1.3 http.IncomingMessage

1.4 http.ServerResponse

 1.5 http.ClientRequest

1.6 使用axios

2 Http协议

2.1 请求报文

 请求行

其他请求方式

请求头

空行

请求体

2.2 响应报文 

状态行

响应头

空行

响应体

3 Http缓存机制

 3.1 http1.0、http1.1、http2.0

4 三次握手

 5 四次挥手


学习目标:
http模块api
http协议
http缓存机制
三次握手四次挥手


1 Http模块

要使用 HTTP 服务器和客户端,则必须 require('http') 。

const http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, { 'Content-Type':
'application/json;charset = UTF-8' });
response.write("你好");
response.end();
}).listen(8888, '127.0.0.1');

1.1 http
http.METHODS

解析器支持的 HTTP 方法列表。

const http = require('http');
console.log(http.METHODS);

结果为:

 http.STATUS_CODES

所有标准 HTTP 响应状态代码的集合,以及每个的简短描述。 例
如, http.STATUS_CODES[404] === 'Not Found' 。

const http = require('http');
console.log(http.STATUS_CODES);

结果为:

{
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'103': 'Early Hints',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'205': 'Reset Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'226': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent 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 Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': "I'm a Teapot",
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'425': 'Too Early',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'509': 'Bandwidth Limit Exceeded',
'510': 'Not Extended',
'511': 'Network Authentication Required'
}

http.createServer(options[, requestListener]

创建服务,requestListener中的参数类型为ClientRequest,ServerResponse。返回
http.Serverhttp.Server 的新实例。
requestListener 是自动添加到 'request''request' 事件的函数。

const http = require('http');
// 创建本地服务器来从其接收数据
const server = http.createServer((req, res) => {
console.log(req.constructor); // [Function: IncomingMessage]
console.log(res.constructor); // [Function: ServerResponse]
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
data: 'Hello World!'
}));
});
server.listen(8000);
console.log(server.constructor); //[Function: Server]

在浏览器访问该服务器:

 http.request(options[, callback])

发送requet请求,callba ck中的参数类型为IncomingMessage
http.get(url[,options, callback])
客户端发送请求,由于多数请求都是get请求,get请求没有请求体,nodejs提供了
http.get这个简便方法。callback中的参数类型为IncomingMessage

1.2 http.Server

调用http.createServer()方法返回的就是【Server】类型的实例。
事件: upgrate
事件: connect
事件: connection
事件: request
server.headersTimeout
server.maxHeadersCount
server.requestTimeout
server.timeout
server.keepAliveTimeout
server.listen()
server.close()
server.setTimeout([msecs][, callback])

1.3 http.IncomingMessage

http.IncomingMessage类也是被动创建的,是由http.Server类和http.ClientRequest类
创建的,并分别作为第一个参数传递给request事件和response事件的监听器,它是
一个可读流的子类。

let server = http.createServer(function(request,response){ ... });

这里的就是 request对象就是【IncomingMessage】类的实例

绑定data事件的监听器对数据进行操作,在数据接收完成之后可以调用end事件监
听器等。

const http = require('http');
http.createServer((req, res) => {
let param = '';
//如果想获取url上携带的参数,可以在req.url来获取。
//获取请求体中的数据用data和end事件
req.on('data', function (chunk) {
param += chunk;
})
req.on('end', function () {
console.log(param);
})
}).listen(8000, () => {
console.log('8000端口');
})

事件:data 当请求接收到数据片段
事件:end 当请求接收到完数据
事件:response 当请求完成获取响应对象
message.url 获取请求的路径及参数
message.method 获取请求方法
message.statusCode
message.statusMessage
message.rawHeaders
message.headers
message.httpVersion

1.4 http.ServerResponse

该实例创建于服务器端,用于封装或封装了服务器端响应信息。

let server = http.createServer(function(request,response){ ... });

这里的response对象就是【ServerRespons】类的实例

事件:data
response.write(chunk[, encoding][, callback])
写入响应数据
response.end([data[, encoding]][, callback]) 表示当前response已经完成响应头、响应体的发送

response.flushHeaders() 刷新response的响应头
response.writeHead(statusCode[, statusMessage][, headers])
写入响应头
response.getHeader(name) 获取响应头信息
response.getHeaderNames() 获取响应头key值集合
response.getHeaders() 获取响应头
response.hasHeader(name) 判断响应头信息中是否包含name
response.removeHeader(name) 从响应头信息中移除key为name的值
response.socket 从响应头中获取socket信息
response.statusCode 获取状态码
response.statusMessage 获取状态信息

const http = require('http');
http.createServer((req, res) => {
console.log(req.url);
const { url } = req;
res.writeHead(200, {
"Content-Type": 'application/json;charset=utf-8'
})
if (url === '/user/findAll') {
res.write(JSON.stringify({
data: [
{ name: 'tom' }, { name: 'lisi' }
]
}))
res.end()
return;
}
res.end('结束');
}).listen(8000)

结果为:

 1.5 http.ClientRequest

http.ClientRequest类是被动创建的,是在使用http.request()和http.get()方法在客户
端向服务器端发起请求(这里的发起请求是指请求信息的创建以及发送等)时创建
并返回的类,一般用于在客户端生成请求消息 ,是可写流的子类,将数据写入到请
求信息中。http.ClientRequest类有一个response事件,用于监听客户端是否收到服
务端的响应。
如果需要在当前Node项目中发送请求访问第三放服务器中的数据,可以使用如
下操作
获取天气(结合聚合数据提供的api):

const http = require('http');
let options = {
host: 'v.juhe.cn',
port: '80',
method: 'GET',
path: '/weather/index?
cityname=%E8%8B%8F%E5%B7%9E&key=3386c4df69d49768f55add15eb17155a',
};
var req = http.request(options, function (res) {
console.log(res.constructor); //[Function: IncomingMessage]
let result = '';
res.on('data', function (chunk) {
result += chunk;
});
res.on('end', function () {
console.log('响应已结束', result);
});
});
req.write('');//往请求体写入数据
req.end();//完成请求并发送

这里的就是 req对象是【ClientRequest】类的实例
这里的就是 res对象是【IncomingMessage】类的实例
客户端请求,该请求对象可以向后台发送请求,后台也可以接受前台发过来的请求
对象。 http.request()返回一个http.ClientRequest对象。
事件:response 当请求完成获取响应对象
request.path 获取请求的路径及参数
request.method 获取请求方法
request.host
request.protocol
request.write(chunk[, encoding, callback])向请求体中可以写入很多数据片段,
encoding表示编码,callback为请求输入写入完成后 调用。Returns true if the
entire data was flushed successfully to the kernel buffer. Returns false if all or part
of the data was queued in user memory. 'drain' will be emitted when the buffer is
free again.

request.end([data, encoding, callback]) 结束发送请求,如果data有数据,表示先
write数据,再end请求
request.writableEnded 请求是否写入完成
request.removeHeader(name) 删除请求头

request.removeHeader('Content-Type');

request.setHeader(name, value) 设置请求头信息,value可以为单值也可以为一
个字符串数组

request.setHeader('Content-Type','application/json');
request.setHeader('Cookie',
['type=ninja','language=javascript']);

request.getHeader(name) 获取请求头信息
request.setTimeout(timeout[, callback]) 设置超时时间
request.destroy([error]) 销毁一个请求
request.destroyed 判断一个请求是否被销毁
request.flushHeaders() 刷新请求头信息到请求中
request.getRawHeaderNames() 获取请求头key值数组

1.6 使用axios

之后可以使用axios来发送请求。就不用使用http.request()发请求了。
在当前文件夹执行 npm init -y 来快速初始化一个node.js项目。

 然后在项目内执行 npm i axios -S 来下载第三方模块axios。

 下载完毕后就可以使用axios来发送请求了。

const axios = require('axios');
async function find() {
let res = await
axios.get('http://124.223.22.76:7001/count/countAll');
console.log(res.data);
}
find();

获取天气(结合聚合数据提供的api):

const axios = require('axios');
const querystring = require('querystring');
async function find() {
let res = await axios.get('http://v.juhe.cn/weather/index?
cityname=' + querystring.escape('苏州') +
'&key=3386c4df69d49768f55add15eb17155a');
console.log(res.data);
}
find();

2 Http协议

HTTP是一种能够获取如 HTML 这样的网络资源的 protocol(通讯协议)。它是在 Web
上进行数据交换的基础,是一种 client-server 协议,也就是说,请求通常是由像浏
览器这样的接受方发起的。一个完整的Web文档通常是由不同的子文档拼接而成
的,像是文本、布局描述、图片、视频、脚本等等。

 HTTP被设计于20世纪90年代初期,是一种可扩展的协议。它是应用层的协议,通
过TCP,或者是TLS-加密的TCP连接来发送,理论上任何可靠的传输协议都可以使
用。因为其良好的扩展性,时至今日,它不仅被用来传输超文本文档,还用来传输
图片、视频或者向服务器发送如HTML表单这样的信息。HTTP还可以根据网⻚需
求,仅获取部分Web文档内容更新网⻚。
HTTP报文的分类有两种:请求报文和响应报文。顾名思义,请求报文就是客户端
向服务端发送请求的信号,响应报文就是服务端响应处理后回传给客户端的信号。

2.1 请求报文

HTTP 请求报文由四部分组成,分别是请求行、请求头、空行和请求体,其中空行
也是组成部分之一,作用是进行分隔,必不可少。

 请求行

第一行为请求行,由请求方法、URI和HTTP协议版本3个字段组成,它们之间用空格
分隔,最后以回⻋和换行符结尾进行内容分割,表示接下来的内容(下一行开始
的)不是请求行的内容。举例,GET /index.php HTTP/1.1,GET是请求方
法,/index.php是URL,HTTP/1.1表示使用的HTTP版本为1.1。

这一行比较好理解,只有请求方法的类型比较多,有GET、POST、HEAD、PUT、
DELETE、OPTIONS、TRACE、CONNECT,其中GET、POST最为常用,这里详细介绍
下。
- GET
GET最为常⻅的请求方式,通常用于当客户端要从服务器中读取文档时,比如点击
网⻚上的链接或者通过在浏览器的地址栏输入网址的方式来浏览网⻚,使用的都是
GET方式。需要注意的是使用GET方法请求时,请求参数和对应的值是跟在URL后
面,通过问号(“?”)和and连接符(“&”)以及“=”号连接。GET方法要求服务器将
URL定位的资源放在响应报文的数据部分,回送给客户端。例如,/index.php?
id=100&slec=yes,这样通过GET方式传递的数据直接表示在地址中。正式因为要传
递的参数和值已经存在于URL中,所以采用GET方法请求的HTTP报文是没有请求体
的。
很明显,GET方法把参数以及参数值都暴露在URL中了,好处显而易⻅,弊端就是
不利于数据的保密和安全。另外浏览器对地址的字符⻓度是有限制的,虽然各自的
标准不同,但一般不超过1024个字符,所以如果要传输的数据量比较大,不宜采用
GET方法。
- POST
POST也是非常常⻅的请求方式,并且完美弥补了GET方法的不足。因为POST方法将
要传输的数据封装在报文的请求体中,并且对传输的数据大小没有限制,所以可以
传输大量的数据,并且因为数据封装在请求体中,没有直接暴露在URL中,所以比
较私密和安全。

其他请求方式

其他请求方式用得比较少,其中HEAD方法偶尔用到,服务端接受到HEAD请求后只
返回响应头,而不会发送响应内容,这样就提高了传输效率。所以当我们只需要查
看某个⻚面的状态的时候,使用HEAD是非常高效的。

请求头

请求头部由键/值对组成,每行一对,键和值用冒号“:”(英文)分隔。请求头部告
知服务器所有有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的用户代理信息(浏览器信息): Mozilla/5.0 (Macintosh;
Intel Mac OS X 10_12_3) AppleWebKit/537.36等;
Accept:客户端可识别的内容类型列 :
text/html,application/xhtml+xml,application/xml;
Accept-Language:客户端可接受的自然语言 - zh-CN,zh;q=0.8,en;q=0.6,id;q=0.4;
Accept-Encoding:客户端可接受的编码压缩格式 - gzip, deflate, sdch, br
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机
connection:连接方式,有close和keep-alive两种。
close:告诉WEB服务器或代理服务器,在完成本次请求的响应后,断开连接
keep-alive:告诉WEB服务器或代理服务器。在完成本次请求的响应后,保持连接,
以等待后续请求
Cookie:存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie -
PSTM=1490844191; BIDUPSID=2145FF54639208435F60E1E165379255;

空行

用户进行内容分割,表示请求头到此为止,下一行的内容不再是请求头。


请求体

请求体包含的就是请求数据,正如上文提到的,当使用的是GET方法的时候,没有
请求体。

2.2 响应报文

客户端向服务端发送请求之后,服务器接收并处理客户端发过来的请求后正常情况
下会返回一个HTTP的响应消息,这个就是响应报文。
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。形
式上除了状态行之外,其他三个部分与请求报文类似。

 

状态行

格式为:HTTP-Version Status-Code Reason-Phrase CRLF。其中,HTTP-Version表示
服务器HTTP协议的版本;Status-Code表示服务器发回的响应状态代码;Reason-
Phrase表示状态代码的文本描述。状态代码由三位数字组成,第一个数字定义了响
应的类别,且有五种可能取值。
1xx:指示信息--表示请求已接收,继续处理。
2xx:成功--表示请求已被成功接收、理解、接受。
3xx:重定向--要完成请求必须进行更进一步的操作。
4xx:客户端错误--请求有语法错误或请求无法实现。
5xx:服务器端错误--服务器未能实现合法的请求。

各类型常⻅状态代码、状态描述的说明如下:
200 OK:客户端请求成功。
400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域
一起使用。
403 Forbidden:服务器收到请求,但是拒绝提供服务。
404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
500 Internal Server Error:服务器发生不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复
正常,举个例子:HTTP/1.1 200 OK(CRLF)。

响应头

和请求报文的请求头类似,响应头也由键值对组成,每行一对,键和值用英文冒号
: 分隔。响应头域允许服务器传递不能放在状态行的附加信息,这些域主要描述服
务器的信息和Request-URI进一步的信息,典型的响应头有:
Server:包含处理请求的原始服务器的软件信息;
Date:服务器日期;
Content-Type:返回的资源类型 (MIME);
Connection:连接方式;
close:连接已经关闭;
keep-alive:连接已保持,在等待本次连接的后续请求;
Cache-Control:缓存控制;
Expires:设置过期时间;
Set-Cookie:设置 Cookie 信息。

空行

作为内容分割,表示以下不再是响应头的内容。


响应体

这个是服务器返回给浏览器的响应信息。

3 Http缓存机制

缓存的种类有很多,其大致可归为两类:私有与共享缓存。共享缓存存储的响应能
够被多个用户使用。私有缓存只能用于单独用户。将主要介绍浏览器与代理缓存,
除此之外还有网关 缓存、CDN、反向代理缓存和负载均衡器等部署在服务器上的缓
存方式,为站点和 web 应用 提供更好的稳定性、性能和扩展性。

 HTTP/1.1定义的 Cache-Control 头用来区分对缓存机制的支持情况, 请求头和响应
头都支持这个属性。通过它提供的不同的值来定义缓存策略。

# 没有缓存
Cache-Control: no-store
# 缓存但需要重新验证:每次有请求发出时,缓存会将此请求发到服务器,服务器端会验证
请求 中所描述的缓存是否过期,若未过期(注:实际就是返回304),则缓存才使用本地缓
存副本。
Cache-Control: no-cache
# 公共缓存,表示该响应可以被任何中间件(比如中间代理、CDN等)缓存
Cache-Control: public
# 私有缓存,表示该响应只能被浏览器缓存
Cache-Control: private
# 表示资源能够被缓存(保持新鲜)的最大时间。
Cache-Control: max-age=31536000

当客户端发起一个请求时,缓存检索到已有一个对应的陈旧资源(缓存副本),则缓
存会先 将此请求附加一个 If-None-Match 头,然后发给目标服务器,以此来检查该
资源副本是否是依 然还是算新鲜的,若服务器返回了 304 (Not Modified)(该响应不
会有带有实体信息),则 表示此资源副本是新鲜的,这样一来,可以节省一些带
宽。若服务器通过 If-None-Match 或 If-Modified-Since判断后发现已过期,那么会带
有该资源的实体内容返回。
If-Modified-Since,和 Last-Modified 一样都是用于记录⻚面最后修改时间的 HTTP 头
信息,只是 Last-Modified 是由服务器往客户端发送的 HTTP 头,而 If-Modified-Since
则是 由客户端往服务器发送的头。If-None-Match的工作原理是在HTTP Response中
添加ETags信 息。

浏览器服务器交互过程:
1. 客户端请求一个⻚面(A)。
2. 服务器返回⻚面A,并在给A加上一个ETag。
3. 客户端展现该⻚面,并将⻚面连同ETag一起缓存。
4. 客户再次请求⻚面A,并将上次请求时服务器返回的ETag一起传递给服务器。
5. 服务器检查该ETag,并判断出该⻚面自上次客户端请求之后还未被修改,直接
返回响应304 (未修改——Not Modified)和一个空的响应体。

 3.1 http1.0、http1.1、http2.0

在HTTP1.0中默认是短连接:每次与服务器交互,都需要新开一个连接!
在HTTP1.1中默认就使用持久化连接来解决:建立一次连接,多次请求均由这个连
接完成!(如果阻塞了,还是会开新的TCP连接的)
HTTP2与HTTP1.1最重要的区别就是解决了线头阻塞的问题!其中最重要的改动
是:多路复用 (Multiplexing)

4 三次握手

http请求是在TCP连接的基础上去进行的。
TCP保证通信的三个步骤:三次握手,传输内容,四次挥手。
三次握手是建立连接的过程,四次挥手是关闭连接的过程。

 

进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定
自己的初始化序列号为后面的可靠性传送做准备。
SYN(Synchronize Sequence Numbers)同步序列编号
ACK (Acknowledge character)确认字符,表示接收到的字符无错误
FIN(Finish)结束编号
MSL( Maximum Segment Lifetime) 表示“最⻓报文段寿命”,它是任何报文在网络
上存 在的最⻓时间,超过这个时间报文将被丢弃。

 5 四次挥手

TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户
端或 服务器均可主动发起挥手动作。

为什么要挥手四次?

当服务端收到客户端的SYN连接请求报文后,可以直接发送
SYN+ACK 报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连
接时,当服务端收到 FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复
一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的
报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值