彻底搞懂HTTP协议 - 天天造轮子

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 彻底搞懂HTTP协议 - 天天造轮子

你将Get的技能


  • 如何调戏百度服务器 - 用自己手写的HTTP协议


  • 如何调戏Chrome浏览器 - 用自己手写的HTTP协议


  • 了解HTTP协议与TCP协议的关系


  • 了解HTTP协议的发明的动机


  • 一个字一个字编写一个HTTP报文


Why


据说前端界有一个到非常有名的面试题叫做


输入一个url发生了什么


如果简单回答大概可以分为


  • DNS解析


  • TCP连接


  • 发送HTTP请求


  • 服务器 HTTP 应答


  • 浏览器解析渲染


  • 连接结束


等几个阶段,当然如果详细拆分每个阶段还会在再次被细分,所谓细节决定成败,你谈的细节越多就说明你的知识越系统。唬住唬不住就看你了,不过这确实是一道非常好的考题。


今天然叔只想谈谈其中的一环。


就是如何在TCP协议之上发送HTTP请求,以及如何应答HTTP请求。


游戏规则


实践才是检验真理的唯一标准。


那么怎么才能验证我们确实可以实现了HTTP协议呢?


我们知道HTTP协议分为Request 和 Response两部分


首先我们会使用 TCP 协议封装 HTTP协议. 通过以下两个标准验证实验是否成功。


  • 【Request请求】的验证标准:   可以收到百度的应答


  • 【Response响应】有效的标准:  可以让Chrome浏览器访问


Where - 网络基础与TCP/IP


第一步我们要先找到我们应该在哪做这个游戏,要不然是不是就是神仙打架。


我们知道网络其实就是使用最少两根导线,将多个网络节点连接起来交换数据。


网络异常,图片无法展示
|


网络异常,图片无法展示
|


可想而知,两个儿子还要打架,那么成千上万的计算机如果要保证他们不打架和平相处,就需要复杂的协议支撑。


网络异常,图片无法展示
|


在计算机世界中如果一个复杂问题通常的解决方式就是分层解决


网络异常,图片无法展示
|


网络异常,图片无法展示
|


其实这个就是OSI参考模型,而实际我们现在的互联网世界是就是这个理论模型的落地叫做TCP/IP协议


网络异常,图片无法展示
|


网络异常,图片无法展示
|


What - TCP与HTTP是什么


什么是TCP通讯?


其实传输层有两种通讯方式分别是TCP和UDP。


两种协议都能够传输数据,区别主要是要不要提前建立连接 TCP就是需要建立连接的一个,好处在于通讯方式比较可靠。所以我们说TCP不丢包。


网络异常,图片无法展示
|


但是UDP也不是没有用武之地,就比如说玩游戏 ,一技能没作用我再按一次就行了,所以延时小比可靠连接更重要,所以早期的游戏很多都看上了UDP协议。


网络异常,图片无法展示
|


对于一门高级编程语言来讲无论是(C++ , Java, JS)一般都是可以基于叫做socket的东西完成数据传输的。


TCP通讯程序


下面我们来个Node小例子。


Client


var net = require("net");
var client = net.connect(3000, () => {
  console.log("连接到服务器!");
});
let n = 3;
const interval = setInterval(() => {
  const msg = "Time " + new Date().getTime();
  console.log("客户端发送: " + msg);
  client.write(msg);
  if (n-- === 0) {
    client.end();
    clearInterval(interval);
  }
}, 500);
client.on("end", function () {
  console.log("断开与服务器的连接");
});


Server


var net = require("net");
var server = net.createServer((connection) => {
  console.log("client connected");
  connection.on("data", (data) => {
    console.log("Server接收: " + data.toString());
  });
  connection.on("end", function () {
    console.log("客户端关闭连接");
  });
  connection.end("Hello I am \r\n");
});
server.listen(3000, function () {
  console.log("server is listening at 3000");
});


网络异常,图片无法展示
|


为什么需要HTTP协议


既然上面我们已经知道了通过TCP可以收发数据,假设我们想做一个类似论坛BBS这样的需求怎么做。


网络异常,图片无法展示
|


我们大体上可以把BBS服务器比作一个存储文本、图片、甚至声音、视频的图书馆。


用户如果想借书或者是还书都应该正确的填写借书单。这样才能保证存取有序。


网络异常,图片无法展示
|


网络异常,图片无法展示
|


显然这种功能TCP协议并没有规定,TCP只是提供了交换数据的可能,相当于打开了借书小窗口。真正要完成借书还书还需要设计一个借书单。其实这个借书单就是HTTP协议。


超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。


下面我们先简单浏览一下HTTP协议你看看是否非常像一个借书单。


网络异常,图片无法展示
|


HTTP协议规则


下面我们来细致讲解HTTP协议


要想看到HTTP报文长什么样子,可以使用curl命令


网络异常,图片无法展示
|


其实HTTP报文就是一个文本,这里面使用分隔符比如空格、回车、换行符来区分他的不同部分。


网络异常,图片无法展示
|


解析HTTP报文


下面我们着手去用代码解析一个HTTP报文。


第一步 拆分请求行、头部、请求体


  • 请求行: 就是第一行 -  第一个回车符和换行符前的字符都是请求行


  • 头部: 请求行之后一直到遇到一个空行 -- 其实就是遇到两个连续的回车符和换行符


  • 请求体: 剩下的部分


private parse(): void {
    this.httpMessage = {} as HttpMessage;
    const messages = this.message.split('\r\n');
    const [head] = messages;
    const headers = messages.slice(1, -2);
    const [body] = messages.slice(-1);
    this.parseHead(head);
    this.parseHeaders(headers);
    this.parseBody(body);
  }


第二步 解析请求行


请求结构就是  : 请求方法 + 【空格】+ URL  +【空格】+ 版本号


private parseHead(headStr) {
    const [method, url, version] = headStr.split(' ');
    this.httpMessage.method = method;
    this.httpMessage.url = url;
    this.httpMessage.version = version;
  }


第三步 解析头部


头部的结构:


KEY_A : VALUE


KEY_A : VALUE


KEY_C : VALUE


function parseHeaders(headers) {
    this.httpMessage.headers = {};
    for (let i = 0; i < headers.length; i++) {
      const header = headers[i];
      const [key, value] = header.split(":");
      key = key.toLocaleLowerCase();
      value = value.trim();
      this.httpMessage.headers[key] = value;
    }
  }


请求体


请求体就是剩下的部分无需解析


拼装HTTP响应


拼装的过程其实就是将整个过程反过来进行


function format() {
  const head = `${this.version} ${this.status} ${this.message}`;
  let headers = '';
  for (let key in this.headers) {
  const value = this.headers[key];
  headers += `${key.toLocaleLowerCase()}: ${value}\r\n`;
  }
  const combineData = [head, headers, this.body].join('\r\n');
  return combineData;
}


实现HTTP访问百度首页


下面利用刚才写好的HTTP函数拼装一个报文调戏一下【 百度 】


const net = require("net");
const createFormater = require("./http/formater");
const formater = createFormater("request");
const req = {
  method: "GET",
  url: "/",
  version: "HTTP/1.1",
  headers: { "user-agent": "curl/7.71.1", accept: "*/*" },
  body: "",
};
console.log(formater.format(req))
const client = net.connect(80, "www.baidu.com", () => {
  console.log("连接到服务器!");
  client.write(formater.format(req));
});
client.on("data", function (data) {
  console.log(data.toString());
  client.end();
});
client.on("end", function () {
  console.log("断开与服务器的连接");
});


大家注意这段程序并没有用http协议 ,而只是向百度发送了一个tcp请求,使用的报文也是刚才我自己实现的。结果百度服务器真的应答了。调戏成功,说明我们的HTTP协议实现的不错。


网络异常,图片无法展示
|


实现能被Chrome访问的HTTP服务器


下面我们再来试试这个程序是否能够经受住chrome的考验


const net = require("net");
const createFormater = require("./http/formater");
const formater = createFormater("response");
const res = {
  version: "HTTP/1.1",
  status: "200",
  message: "OK",
  headers: {
    date: "Sat, 04 Dec 2021 14",
    connection: "keep-alive",
    "keep-alive": "timeout=5",
    // "content-length": "19",
  },
  body: "<h1> Hello HTTP<h1>",
};
const server = net.createServer(function (connection) {
  console.log("client connected");
  connection.on("data", (data) => {
    console.log(data.toString());
  });
  connection.on("end", function () {
    console.log("客户端关闭连接");
  });
  connection.end(formater.format(res));
});
server.listen(3000, function () {
  console.log("server is listening");
});


网络异常,图片无法展示
|


服务器发送请求后向浏览器发送了自己组装的应答,浏览器正确渲染的页面。这个实验也可以认为是成功的。


总结回顾


目前虽然简单的实现了HTTP协议但是还很初级,后续还会补充


  • 图片、视频、音频数据


  • cookie-session鉴权


  • 缓存实现


  • 分包上传


  • 管线化


  • Http2.0


相关文章
|
3月前
|
缓存 应用服务中间件 网络安全
Nginx中配置HTTP2协议的方法
Nginx中配置HTTP2协议的方法
205 7
|
15天前
|
缓存 网络协议 前端开发
Web 性能优化|了解 HTTP 协议后才能理解的预加载
本文旨在探讨和分享多种预加载技术及其在提升网站性能、优化用户体验方面的应用。
Web 性能优化|了解 HTTP 协议后才能理解的预加载
|
21天前
|
XML JSON 前端开发
HTTP协议,Content-Type格式介绍篇
通过理解和正确使用Content-Type头字段,可以确保数据在网络上传输时的正确性和高效性,提升网络应用的可靠性和用户体验
92 28
|
19天前
|
XML JSON 前端开发
HTTP协议,Content-Type格式介绍篇
通过理解和正确使用Content-Type头字段,可以确保数据在网络上传输时的正确性和高效性,提升网络应用的可靠性和用户体验。
141 25
|
22天前
|
XML JSON 前端开发
HTTP协议,Content-Type格式介绍篇
通过理解和正确使用Content-Type头字段,可以确保数据在网络上传输时的正确性和高效性,提升网络应用的可靠性和用户体验。
194 18
|
2月前
|
域名解析 缓存 网络协议
Web基础与HTTP协议
通过掌握这些基础知识和技术,开发者可以更加高效地构建和优化Web应用,提供更好的用户体验和系统性能。
79 15
|
2月前
|
前端开发 网络协议 安全
【网络原理】——HTTP协议、fiddler抓包
HTTP超文本传输,HTML,fiddler抓包,URL,urlencode,HTTP首行方法,GET方法,POST方法
|
2月前
|
网络协议 安全 网络安全
探索网络模型与协议:从OSI到HTTPs的原理解析
OSI七层网络模型和TCP/IP四层模型是理解和设计计算机网络的框架。OSI模型包括物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,而TCP/IP模型则简化为链路层、网络层、传输层和 HTTPS协议基于HTTP并通过TLS/SSL加密数据,确保安全传输。其连接过程涉及TCP三次握手、SSL证书验证、对称密钥交换等步骤,以保障通信的安全性和完整性。数字信封技术使用非对称加密和数字证书确保数据的机密性和身份认证。 浏览器通过Https访问网站的过程包括输入网址、DNS解析、建立TCP连接、发送HTTPS请求、接收响应、验证证书和解析网页内容等步骤,确保用户与服务器之间的安全通信。
125 3
|
2月前
|
缓存 网络协议 算法
从零开始掌握HTTP协议
本文介绍HTTP协议的演变,从HTTP1.0到HTTP2.0。HTTP1.0为无状态连接,每次请求独立;HTTP1.1引入持久连接、管道化请求和更多状态码;HTTP2.0采用二进制分帧、多路复用、头部压缩及服务器主动推送,大幅提升性能与用户体验。了解这些区别有助于开发者优化应用和服务。
|
3月前
|
开发者
HTTP 协议请求方法的发展历程
【10月更文挑战第21天】
105 45