We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
http是比较重要的一个模块,是建立服务器的基础,学好这个模块非常重要,首先知道http是应用层协议,那么与net模块相比,相比只是多了http协议报文解析的步骤、同时将解析的内容和stream进行结合,让我们更加方便使用http模块进行数据通信。
Agent 负责管理 HTTP 客户端的连接持久性和重用。 它为给定的主机和端口维护一个待处理请求队列,为每个请求重用单独的套接字连接,直到队列为空,此时套接字被销毁或放入连接池,以便再次用于请求到同一个主机和端口。 销毁还是放入连接池取决于 keepAlive 选项 连接池中的连接已启用 TCP Keep-Alive,但服务器仍可能关闭空闲连接,在这种情况下,它们将从连接池中删除,并且当为该主机和端口发出新的 HTTP 请求时将建立新连接。 服务器也可以拒绝通过同一连接允许多个请求,在这种情况下,必须为每个请求重新建立连接,并且不能放入连接池。 Agent 仍将向该服务器发出请求,但每个请求都将通过新连接发生。 当客户端或服务器关闭连接时,它将从连接池中删除。 连接池中任何未使用的套接字都将被销毁,以便当没有未完成的请求时不用保持 Node.js 进程运行。 (参阅 socket.unref())。 当不再使用时最好 destroy() Agent 实例,因为未使用的套接字会消耗操作系统资源。
Agent 负责管理 HTTP 客户端的连接持久性和重用。 它为给定的主机和端口维护一个待处理请求队列,为每个请求重用单独的套接字连接,直到队列为空,此时套接字被销毁或放入连接池,以便再次用于请求到同一个主机和端口。 销毁还是放入连接池取决于 keepAlive 选项
Agent
keepAlive
连接池中的连接已启用 TCP Keep-Alive,但服务器仍可能关闭空闲连接,在这种情况下,它们将从连接池中删除,并且当为该主机和端口发出新的 HTTP 请求时将建立新连接。 服务器也可以拒绝通过同一连接允许多个请求,在这种情况下,必须为每个请求重新建立连接,并且不能放入连接池。 Agent 仍将向该服务器发出请求,但每个请求都将通过新连接发生。
当客户端或服务器关闭连接时,它将从连接池中删除。 连接池中任何未使用的套接字都将被销毁,以便当没有未完成的请求时不用保持 Node.js 进程运行。 (参阅 socket.unref())。
socket.unref()
当不再使用时最好 destroy() Agent 实例,因为未使用的套接字会消耗操作系统资源。
destroy()
net.createConnection
keep-alive
此对象由 http.request() 内部创建并返回。 它表示正在进行的请求,且其请求头已进入队列。 请求头仍然可以使用 setHeader(name, value)、getHeader(name) 或 removeHeader(name) 改变。 实际的请求头将与第一个数据块一起发送,或者当调用 request.end() 时发送。 要获得响应,则为请求对象添加 'response' 事件监听器。 当接收到响应头时,将、则会从请求对象触发 'response' 事件。 'response' 事件执行时有一个参数,该参数是 http.IncomingMessage 的实例。 在 'response' 事件期间,可以添加监听器到响应对象,比如监听 'data' 事件。 如果没有添加 'response' 事件处理函数,则响应将被完全丢弃。 如果添加了 'response' 事件处理函数,则必须消费完响应对象中的数据,每当有 'readable' 事件时调用 response.read()、或添加 'data' 事件处理函数、或通过调用 .resume() 方法。 在消费完数据之前,不会触发 'end' 事件。 此外,在读取数据之前,它将占用内存,最终可能导致进程内存不足的错误。 Node.js 不检查 Content-Length 和已传输的主体的长度是否相等。
此对象由 http.request() 内部创建并返回。 它表示正在进行的请求,且其请求头已进入队列。 请求头仍然可以使用 setHeader(name, value)、getHeader(name) 或 removeHeader(name) 改变。 实际的请求头将与第一个数据块一起发送,或者当调用 request.end() 时发送。
http.request()
setHeader(name, value)
getHeader(name)
removeHeader(name)
request.end()
要获得响应,则为请求对象添加 'response' 事件监听器。 当接收到响应头时,将、则会从请求对象触发 'response' 事件。 'response' 事件执行时有一个参数,该参数是 http.IncomingMessage 的实例。
'response'
http.IncomingMessage
在 'response' 事件期间,可以添加监听器到响应对象,比如监听 'data' 事件。
'data'
如果没有添加 'response' 事件处理函数,则响应将被完全丢弃。 如果添加了 'response' 事件处理函数,则必须消费完响应对象中的数据,每当有 'readable' 事件时调用 response.read()、或添加 'data' 事件处理函数、或通过调用 .resume() 方法。 在消费完数据之前,不会触发 'end' 事件。 此外,在读取数据之前,它将占用内存,最终可能导致进程内存不足的错误。
'readable'
response.read()
.resume()
'end'
Node.js 不检查 Content-Length 和已传输的主体的长度是否相等。
此类继承自 net.Server 并具有以下额外的事件:
net.Server
Expect
'error'
此对象由 HTTP 服务器在内部创建,而不是由用户创建。 它作为第二个参数传给 'request' 事件。
'request'
IncomingMessage 对象由 http.Server 或 http.ClientRequest 创建,并分别作为第一个参数传给 'request' 和 'response' 事件。 它可用于访问响应状态、消息头、以及数据。
IncomingMessage
http.Server
http.ClientRequest
可以这样理解,一共包含Server、Agent、ServerResponse、IncomingMessage、ClientRequest
Server
ServerResponse
ClientRequest
ClientRequst
stream.Readable
stream.Writable
request
我们知道http.Server继承与net.Server,那么相比net.Server只是多了一个解析包装过程,因为Http是应用层协议,所以当我们通过net.Server拿到数据之后,我们需要根据数据解析出Http的相关参数,先监听socket的data事件,然后等事件发生的时候,进行解析 解析出请求头,在创建请求对象,再根据请求对象创建响应对象
对于前端应用,HTTP请求瞬间数量比较多,但每个请求传输的数据一般不大;这时,用同一个TCP连接处理同一个用户发出的HTTP请求可以显著提高性能。但是keep-alive也不是万能的,如果用户每次只发起一个请求,它反而会因为延长连接的生存时间,浪费服务器资源。
针对同一个连接,Node.js会维持一个incoming队列和一个outgoing队列。应用程序通过监听request事件,可以访问ServerResponse和IncomingMessage对象,当请求处理完成之后(调用response.end()),ServerResponse会响应finish事件。如果它是本次连接上最后一个response对象,则准备关闭连接;否则,继续触发request事件。每个连接最长超时时间默认为2分钟,可以通过http.Server.setTimeout调整。 现在把我们的Node.js版hello world修改一下
如果客户端在发送POST请求之前,由于传输的数据量比较大,期望向服务器确认请求是否能被处理;这种情况下,可以先发送一个包含头Expect:100-continue的http请求。如果服务器能处理此请求,则返回响应状态码100(Continue);否则,返回417(Expectation Failed)。默认情况下,Node.js会自动响应状态码100;同时,http.Server会触发事件checkContinue和checkExpectation来方便我们做特殊处理。具体规则是:当服务器收到头字段Expect时:如果其值为100-continue,会触发checkContinue事件,默认行为是返回100;如果值为其它,会触发checkExpectation事件,默认行为是返回417。
在实际开发时,用到http代理的机会还是挺多的,比如,测试说线上出bug了,触屏版页面显示有问题;我们一般第一时间会去看api返回是否正常,这个时候在手机上设置好代理就能轻松捕获HTTP请求了。老牌的代理工具有fiddler,charles。其实,nodejs下也有,例如node-http-proxy,anyproxy。基本思路是监听request事件,当客户端与代理建立HTTP连接之后,代理会向真正请求的服务器发起连接,然后把两个套接字的流绑在一起。我们可以实现一个简单的代理服务器
import http, { Agent, ClientRequest, Server, ServerResponse, IncomingMessage, RequestOptions } from 'http'; import net from 'net'; import url from 'url'; // 实现一个代理服务器 const PORT = 8000; const server = http.createServer((req, res) => { if (!req.url) { return }; const urlOption = url.parse(req.url); const options: RequestOptions = { host: urlOption.host, port: urlOption.port || 80, method: req.method, headers: req.headers, path: urlOption.path, }; const clientRequest = http.request(options, (clientRes) => { clientRes.pipe(res); }) req.pipe(clientRequest); }) server.listen(PORT, () => { console.log(`代理服务器开启,监听端口${PORT}`); })
完整的代理服务器请参见下一节的实现,现在只是简单的实现,没有针对代理服务器的相关报文进行处理。
为了确保数据通信的安全,HTTPS已广泛应用于互联网,浏览器与服务器之间的HTTPS通信都是加密的。然而当浏览器需要通过代理服务器发起HTTPS请求时,由于请求的站点地址和端口号都是加密保存于HTTPS请求头中的,代理服务器是如何既确保通信是加密的(代理服务器自身也无法读取通信内容)又知道该往哪里发送请求呢?为了解决这个问题,浏览器需要先通过明文HTTP形式向代理服务器发送一个CONNECT请求告诉它目标站点地址及端口号。当代理服务器收到这个请求后,会在对应的端口上与目标站点建立一个TCP连接,连接建立成功后返回一个HTTP 200状态码告诉浏览器与该站点的加密通道已建成。接下来代理服务器仅仅是来回传输浏览器与该服务器之间的加密数据包,代理服务器并不需要解析这些内容以保证HTTPS的安全性,这个通道就是隧道代理。
connect请求主要用于代理,通过connect请求告诉代理,客户端接下去可能要建立一条HTTPS隧道,不要干扰我的数据。所以一般都是用户通过代理发起和目标网站的SSL握手从而进行HTTPS数据传输。
CONNECT请求是浏览器发给HTTP代理的,实质内容只有目标服务器的域名与端口,意思是请求代理建立一条到目标服务器的该端口的TCP连接,然后代理会在浏览器与目标服务器之间做字节流盲转发。
CONNECT
connect
https://github.com/yjhjstz/deep-into-node/blob/master/chapter10/chapter10-1.md
代理头部分析
理解http connect请求
The text was updated successfully, but these errors were encountered:
No branches or pull requests
http
http是比较重要的一个模块,是建立服务器的基础,学好这个模块非常重要,首先知道http是应用层协议,那么与net模块相比,相比只是多了http协议报文解析的步骤、同时将解析的内容和stream进行结合,让我们更加方便使用http模块进行数据通信。
文档部分
(1) Agent类(类似工具类)
net.createConnection
相同keep-alive
选项,最好在代理不在使用这些socket的时候调用, 否则,在服务器终止套接字之前,套接字可能会挂起很长时间。keepAlive
时代理正在等待使用的套接字数组。(2) ClientRequest类
(3) Server类
Expect
请求头的请求时触发'error'
事件,则会在此处转发。 此事件的监听器负责关闭或销毁底层套接字。(4) ServerResponse类
(5) IncomingMessage类
(6) 模块上的方法属性
( 7) 整个类的理解
可以这样理解,一共包含
Server
、Agent
、ServerResponse
、IncomingMessage
、ClientRequest
Server
对应服务器端,ClientRequst
对应客户端Server
继承net.Server
,构造函数接受一个函数,这个函数有两个参数,一个是IncomingMessage
继承于stream.Readable
,一个 是ServerResponse
继承于stream.Writable
,如果不传入函数,需要添加request
事件来处理这个请求Server
和ClientRequest
是一个层级,一个代表一个请求或者一个代表一个服务器,监听他们事件或者他们的回调函数会生成ServerResponse
、IncomingMessage
类型的参数理解部分
(1) http服务器和net.server 中区别
我们知道
http.Server
继承与net.Server
,那么相比net.Server
只是多了一个解析包装过程,因为Http是应用层协议,所以当我们通过net.Server
拿到数据之后,我们需要根据数据解析出Http的相关参数,先监听socket的data事件,然后等事件发生的时候,进行解析 解析出请求头,在创建请求对象,再根据请求对象创建响应对象(2)http场景分析
keep-alive
对于前端应用,HTTP请求瞬间数量比较多,但每个请求传输的数据一般不大;这时,用同一个TCP连接处理同一个用户发出的HTTP请求可以显著提高性能。但是keep-alive也不是万能的,如果用户每次只发起一个请求,它反而会因为延长连接的生存时间,浪费服务器资源。
针对同一个连接,Node.js会维持一个incoming队列和一个outgoing队列。应用程序通过监听request事件,可以访问ServerResponse和IncomingMessage对象,当请求处理完成之后(调用response.end()),ServerResponse会响应finish事件。如果它是本次连接上最后一个response对象,则准备关闭连接;否则,继续触发request事件。每个连接最长超时时间默认为2分钟,可以通过http.Server.setTimeout调整。
现在把我们的Node.js版hello world修改一下
如果客户端在发送POST请求之前,由于传输的数据量比较大,期望向服务器确认请求是否能被处理;这种情况下,可以先发送一个包含头Expect:100-continue的http请求。如果服务器能处理此请求,则返回响应状态码100(Continue);否则,返回417(Expectation Failed)。默认情况下,Node.js会自动响应状态码100;同时,http.Server会触发事件checkContinue和checkExpectation来方便我们做特殊处理。具体规则是:当服务器收到头字段Expect时:如果其值为100-continue,会触发checkContinue事件,默认行为是返回100;如果值为其它,会触发checkExpectation事件,默认行为是返回417。
在实际开发时,用到http代理的机会还是挺多的,比如,测试说线上出bug了,触屏版页面显示有问题;我们一般第一时间会去看api返回是否正常,这个时候在手机上设置好代理就能轻松捕获HTTP请求了。老牌的代理工具有fiddler,charles。其实,nodejs下也有,例如node-http-proxy,anyproxy。基本思路是监听request事件,当客户端与代理建立HTTP连接之后,代理会向真正请求的服务器发起连接,然后把两个套接字的流绑在一起。我们可以实现一个简单的代理服务器
完整的代理服务器请参见下一节的实现,现在只是简单的实现,没有针对代理服务器的相关报文进行处理。
(3) 隧道代理
为了确保数据通信的安全,HTTPS已广泛应用于互联网,浏览器与服务器之间的HTTPS通信都是加密的。然而当浏览器需要通过代理服务器发起HTTPS请求时,由于请求的站点地址和端口号都是加密保存于HTTPS请求头中的,代理服务器是如何既确保通信是加密的(代理服务器自身也无法读取通信内容)又知道该往哪里发送请求呢?为了解决这个问题,浏览器需要先通过明文HTTP形式向代理服务器发送一个CONNECT请求告诉它目标站点地址及端口号。当代理服务器收到这个请求后,会在对应的端口上与目标站点建立一个TCP连接,连接建立成功后返回一个HTTP 200状态码告诉浏览器与该站点的加密通道已建成。接下来代理服务器仅仅是来回传输浏览器与该服务器之间的加密数据包,代理服务器并不需要解析这些内容以保证HTTPS的安全性,这个通道就是隧道代理。
connect
请求?(4) 参考资料
https://github.com/yjhjstz/deep-into-node/blob/master/chapter10/chapter10-1.md
代理头部分析
理解http connect请求
The text was updated successfully, but these errors were encountered: