一、HTTP的协议解析
1、ISO-OSI七层网络模型
-
应用层
网络服务与最终用户的一个接口。 协议有:HTTP FTP
-
表示层 (五层模型应用层)
数据的表示、安全、压缩。 格式有,JPEG、ASCll、EBCDIC、加密格式等
-
会话层(五层模型应用层)
建立、管理、终止会话。 对应主机进程,指本地主机与远程主机正在进行的会话
-
传输层
定义传输数据的协议端口号,以及流控和差错校验。 协议有:TCP UDP,数据包一旦离开网卡即进入网络传输层
-
网络层 进行逻辑地址寻址,实现不同网络之间的路径选择。 协议有:IP(IPV4 IPV6)
-
数据链路层
建立逻辑连接、进行硬件地址寻址、差错校验 等功能。(由底层网络定义协议) 将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。
-
物理层
建立、维护、断开物理连接。(由底层网络定义协议)

流:无明显分割单位,只保证前后的顺序正确
端口:接到的数据包分给各个应用
require('net'):node依赖库
包:
IP地址:
libnet/libpcap:libnet构造IP包并发送,libpcap从网卡抓所有流经网卡的包

全双工通道不存在优先关系,但是HTTP必须由客户端发起一个request,然后服务端返回response
二、服务端环境准备
-
POST / HTTP/1.1
Request line
-
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencodedheaders
-
field1=aaa&code=x%3D1
body
const http = require('http');
http.createServer((request, response) => {
let body = [];
request.on('error',(err) => {
console.error(err);
}).on('data',(chunk) =>{
body.push(chunk.toString())
}).on('end',()=>{
body = Buffer.concat(body).toString();
console.log('body:',body);
response.writeHead(200,{'Content-T':'text/html'});
response.end("<div style='width:200px;height:200px;background:red'>123</div>")
})
}).listen(8080);
console.log('server started');
三、实现一个HTTP请求
const net = require("net");
class Request {
constructor(option) {
this.method = option.method || 'GET';
this.host = option.host;
this.port = option.port || 80;
this.path = option.path || '/';
this.body = option.body || {};
this.headers = option.headers || {};
if(!this.headers["Content-Type"]){
this.headers["Content-Type"] = "application/x-www-form-urlencoded"
}
if(this.headers["Content-Type"] ==="application/json"){
this.bodyText = JSON.stringify(this.body)
}else if(this.headers["Content-Type"] === "application/x-www-form-urlencoded"){
this.bodyText = Object.keys(this.body).map(key => `${key}=${encodeURIComponent(this.body[key])}`).join('&')
}
this.headers["Content-Length"] = this.bodyText.length;
}
send(){
return new Promise((resolve, reject) => {
//.....
});
}
}
void async function () {
let request = new Request({
method: "POST",
host: "127.0.0.1",
port: "8088",
path: "/",
headers: {
["X-Foo2"]: "customed"
},
body: {
name: 'Midsummer'
}
})
let response = await request.send();
console.log(response);
}()

四、send函数编写,了解response格式

- state line HTTP/1.1 200(HTTP状态码) OK(状态文本)
- headers
- body

五、发送请求

六、response解析
- Response必须分段构造,所以我们要用一个ResponseParser来“装配”
- ResponseParser分段处理ResponseText,我们用状态机来分析文本的结构
七、response body解析
- Response的body可能根据Content-Type有不同的结构,因此我们会采用子Parser的结构来解决问题
- 以TrunkedBodyParser为例,我们同样用状态机来处理body的格式