前两篇文章,我们从空间和时间的角度都对HTTP有了一定的学习和理解,那么基于上一篇的HTTP发展的时间顺序,我会在后面的文章由浅入深,按照HTTP版本内容的更迭,一边介绍相关字段的使用方法,一边讲解其特性和目的,并和大家一起手写测试代码,学以致用。

  当然在真正进入时间线之前,我们还还需要一些前置内容,本篇呢,会先带大家去手写一下HTTP的一个小栗子及相关配置修改方式。然后我还会根据测试的HTTP请求带大家先熟悉一下HTTP的基本内容。

  这就是本篇的所有内容啦~本来还想把HTTP的特点和方法也写进来,但是觉得篇幅可能会太长,所以还是另起一篇吧。

一、一个小的不能再小的小栗子

  其实这个小栗子的代码十分简单,我们主要使用Node来作为服务器端。然后还需要修改一下下本地的Hosts文件。废话不多说,想必大家的大刀都饥渴难耐了吧,啊哈哈哈哈。

  我们先来把测试代码写好,简单的一批,我是直接从Node官网的文档的首页直接复制下来的:

const http = require("http");

const hostname = "127.0.0.1";
const port = 8080; const server = http.createServer((req, res) => {
res.end("Hello Zaking World!This is Node");
}); server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});

  这段代码十分简单哈,就是启动个服务,然后服务器返回一段字符串就完事了。然后我们直接在命令行中执行这段代码的文件:

node ./server.js

  嗯,你可以看到这个文件的文件名叫做server。启动成功后,我们直接打开浏览器在地址栏输入http://127.0.0.1:8080/,就可以直接看到浏览器中显示出了结果:

  很顺利,很完美~到了这一步,其实你已经完成并体验了HTTP/0.9的所有内容。Get请求,返回字符串。但是现在还只是通过本地的ip来访问我们启动的服务,我们要在本地模拟一下域名,直接通过域名来访问我们启动的Node服务,实验一下Get请求。

  首先,我们找一下本机的hosts文件。Windows的hosts文件在这里:C:\WINDOWS\system32\drivers\etc\hosts。你可以直接复制下来在windows里搜索,注意保存的时候需要管理员权限,而mac的地址则是在这里:/etc/hosts。可以通过命令行:open /etc/hosts打开后修改,也可以直接找到文件后修改。你可以在hosts中加一行,修改成这样:

127.0.0.1       www.zaking.com

  然后,别忘了用管理员权限保存一下,我们直接打开浏览器,输入www.zaking.com:8080。当然,这个域名你可以随便起,就是本地自己玩嘛。我们可以看到浏览器同样获取到了我们想要的内容:

  为什么我们加了hosts的配置之后,就可以在本地通过域名来访问我们启动的服务了呢?其实简单来说,就是域名解析的过程。当浏览器访问www.zaking.com的时候,发现这不是一个ip那就肯定是域名了,于是会尝试去访问一系列的域名服务器,把这个域名转换成ip,但是由于整个域名解析的体系实在是很复杂,如果每次都去访问服务器确定域名对应的ip,那实在是慢死了。于是为了解决慢的问题,就出现了缓存,当浏览器尝试去获取对应域名的ip的时候,会先去浏览器自己的缓存里看看有没有这个域名的IP,没有就去操作系统里找,再没有,就会去检查本机的域名解析文件,也就是hosts,于是,找到了就直接转换成这个对应的ip了。

  那要是本机没找到呢?那没办法,就得一级一级的去域名服务器找对应的ip啦。

  OK,我们的基本例子代码和最最最简单的实验都做完了。接下来的篇章我们都基于这个最简单的例子,去试验各个HTTP的核心重点。

二、HTTP报文的组成

  还记得我们在空间穿梭的时候说过,当发送请求的时候,会在HTTP报文的基础上每一层都会加上上一层的头信息,然后当服务器获取,路过各层的时候,会拆下来各层需要的头信息。那HTTP其实也类似,也需要在传输的数据前附加一些头数据。唯一不太一样的是,HTTP的这些头数据,是纯文本,也就是ASCII码,所以这些数据用肉眼就能分辨,不需要借助解析工具。

  HTTP协议是基于请求—响应的模型,所以头数据也分为请求报文和响应报文。这两种报文的结构也是基本相同的,都由三大部分组成:

  • 起始行(start line):描述请求或响应的基本信息
  • 头部字段集合(header):使用key-value的形式更详细的说明报文
  • 消息正文(entity):实际传输的数据,不一定只是文本,可能是图片、视频等二进制文件。

  看起来好像有点复杂,在通常情况下,我们会把起始行和头字段统一叫做请求头或者响应头,也就是header,而传输的数据就叫做body。这样看起来是不是简单了些。

  我还记得我说要按照HTTP的历史时间顺序来讲解HTTP,所以,现在应该讲的是HTTP/0.9,但是HTTP/0.9又太少了,所以我只能把它包含在这里了。

  后面,我会按照总分的方式来讲后续的内容,总的就是总体的介绍、比如HTTP的方法、状态码、特点等等,分的部分呢,则是按照时间顺序来讲解头字段。这样,体系就清晰了。

  不多啰嗦啦,我们继续~

一)起始行

  起始行这个东西其实有两种叫法,发送请求的起始行就叫做请求行,发送响应的起始行就叫做状态行。我们分别来看下他们的区别。

  我们来看张图:

  这就是我们上面的基础例子的HTTP请求的详细headers。诶?你这糊弄我呢?你这也没有啥请求行啊,不都是头字段么?糊弄我不懂呢?嗯……你看我后面慢慢给你编,上面这个图先看下就好,咱们每天都接触,不看也行啦。

1、请求行

  请求行由三部分构成,分别是:

  • 请求方法:通常是一个动词,表示对服务器资源的操作,比如GET、POST等。
  • 请求目标:通常是一个URI,标记了目标资源的地址。
  • 版本号:表示报文使用的协议版本。

  你还记得HTTP的一个描述是:HTTP是使用纯文本传输的,那么在文本中,如何分割各个字段呢?嗯……就是空格,用空格来分割请求方法、请求目标以及版本号,然后,再用一个换行符来作为请求行结束的标记。

  我们还是回到之前的例子中:

  看到跟之前的图有什么区别了吗?这就是请求行原始的样子,而我们上图中看到的是parsed之后的,也就是经过了格式化,让我们看起来更舒服。而source则可以让我们看到报文的原始样子。

  而在请求行中,实际上我们要重点关注的就是请求方法,这个我们下一章再说,我们先知道请求行都有哪些内容就好啦。

2、状态行

  响应报文中的起始行不叫响应行,而是叫状态行,状态行也有三部分:

  • 版本号:嗯,就是跟请求行中一样。
  • 状态码:一个三位数字,用来表示请求处理的结果,比如200、300、400啥的。
  • 原因:作为状态码的补充,就像一个说明。

  状态行就像这样:

  那你知道为啥响应报文中的起始行不叫响应行了不?重点就在这个状态码,告诉你对于当前请求的处理结果的状态。而状态码和原因则往往是配对出现的。

  那么请求中有“方法”,响应中有“状态”。刚好,来回都描述的很完整。

二)头字段

  请求行或者状态行再加上头字段,就是完整的请求头或者响应头。请求头和响应头的头字段基本上是一致的,都是一种key-value形式的键值对。但是头字段有以下几点需要注意一下:

  • 字段名不区分大小写,Host还是host还是HOST都是一个意思,但是通常我们会首字母大写,便于阅读与理解。
  • 字段名里不能出现空格,可以有连字符“-”,但是不能有下划线“_”。
  • 字段名后面必须紧跟着“:”,不能有空格,而“:”后面可以随意空格。
  • 顺序是无意义的,随便。
  • 原则上字段名不能重复,除非本身的语义允许。

  HTTP协议规定了好多好多的头字段,甚至我们还可以自定义头字段,但是通常头字段可以分为以下几类:

  • 通用字段,请求头和响应头中都可以使用
  • 请求字段,当然只能在请求头中用。
  • 响应字段,当然只能出现在响应头中。
  • 实体字段,其实算是通用字段,往往是为了描述传输的数据的额外的信息。

  所以你看,原则上字段的类型就三种,要么只有我能用,要么只有你能用,要么就都能用。

  当然,还有一种情况是往往有些字段不是独立出现的,而是有一定的配合~我们后面会详细聊哒。

三)实体

  实体,其实就是我们在使用HTTP的时候传输的数据内容,我们通常把它叫做body,当然,我们也可以通过GET方法来传递一定数据量的信息,0.9就是这样做的,但是毕竟这算不上是“正途”,如果我想要传音频、视频、图片咋整?总不能也用GET请求放在URL的query里吧?

  这就需要我们的body了,但是body要怎么传呢?我传给你服务器一个视频文件,但是服务器怎么知道要按照什么样的方式来解析这个文件呢?嗯……可以根据文件的后缀吖,没错,那我要是改了后缀名呢?我就故意改,你能咋整,所以这种方法也不那么靠谱。

  然后,其实某一个类型的文件的二进制编码的前面一小部分其实是固定的,我们也可以根据这些固定的数据来判断,但是这样也好像不是那么靠谱,而且还有点低效,还有很大概率查不出来。

  那咋整,那就是MIME type,MIME是一个很大的标准规范,HTTP拿取了其中的一部分用来表示body的数据类型。那啥是MIME呢?嗯,它的大名叫做“多用途互联网邮件扩展”(Multipurpose Internet Mail Extensions),本来是给电子邮件用的,目的是为了让电子邮件可以发送出了ASCII码以外的任意数据。

  MIME把数据分为了八大类,每个大类下面还有子类,大概是这样的:type/subtype。就很符合HTTP的标准要求,于是就顺手牵羊拿过来了。

  在HTTP中常用的大概有text、image、audio/video、application等。最常见的大家也最熟悉的想必就是application/json啦。

  至于具体每一个字段的详细解释,我会在后面讲解到对应字段的时候再加以详述。

三、小小结

  我们稍稍回顾一下本篇我们都学习了哪些内容。

  首先,我带大家完成了一个小小小栗子,看了一下GET请求。

  然后,依赖于这个小小小栗子,我们知道了HTTP的组成有哪三部分或者哪两部分。

  最后我问大家一个问题:你知道起始行中的重点内容有哪些么?

  我们下一篇再见~嘿嘿

真正“搞”懂HTTP协议04之搞起来的更多相关文章

  1. 真正“搞”懂HTTP协议02之空间穿梭

    时隔四年,这个系列鸽了四年,我终于觉得我可以按照自己的思路和想法把这个系列完整的表达出来了. 想起四年前,那时候还是2018年的六月份,那时候我还工作不到两年,那时候我翻译了RFC2616的部分内容, ...

  2. 真正“搞”懂http协议01—背景故事

    去年读了<图解HTTP>.<图解TCP/IP>以及<图解网络硬件>但是读了之后并没有什么深刻的印象,只是有了一层模糊的脉络,刚好最近又接触了一些有关http的相关内 ...

  3. 真正“搞”懂HTTP协议03之时间穿梭

    上一篇我们简单的介绍了一下DoD模型和OSI模型,还着重的讲解了TCP的三次握手和四次挥手,让我们在空间层面,稍稍宏观的了解了HTTP所依赖的底层模型,那么这一篇,我们来追溯一下HTTP的历史,看一看 ...

  4. [转帖]USB-C和Thunderbolt 3连接线你搞懂了吗?---没搞明白.

    USB-C和Thunderbolt 3连接线你搞懂了吗? 2018年11月25日 07:30 6318 次阅读 稿源:威锋网 3 条评论 按照计算行业的风潮,USB Type-C 将会是下一代主流的接 ...

  5. 搞懂Redis协议RESP

    RESP (REdis Serialization Protocal) Redis客户端和服务端之间通信的协议.它很简单,建立在TCP协议上,提供简单.高性能.可读性强的数据序列化的规范和语义. 5种 ...

  6. 搞懂分布式技术4:ZAB协议概述与选主流程详解

    搞懂分布式技术4:ZAB协议概述与选主流程详解 ZAB协议 ZAB(Zookeeper Atomic Broadcast)协议是专门为zookeeper实现分布式协调功能而设计.zookeeper主要 ...

  7. 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法

    搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...

  8. 搞懂分布式技术21:浅谈分布式消息技术 Kafka

    搞懂分布式技术21:浅谈分布式消息技术 Kafka 浅谈分布式消息技术 Kafka 本文主要介绍了这几部分内容: 1基本介绍和架构概览 2kafka事务传输的特点 3kafka的消息存储格式:topi ...

  9. 搞懂分布式技术28:微服务(Microservice)那点事

    搞懂分布式技术28:微服务(Microservice)那点事 微服务(Microservice)那点事 肥侠 2016-01-13 09:46:53 浏览58371 评论15 分布式系统与计算 微服务 ...

  10. 搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务

    搞懂分布式技术19:使用RocketMQ事务消息解决分布式事务 初步认识RocketMQ的核心模块 rocketmq模块 rocketmq-broker:接受生产者发来的消息并存储(通过调用rocke ...

随机推荐

  1. OpenJudge1.5.17

    20:球弹跳高度的计算 总时间限制: 1000ms 内存限制: 65536kB 描述 一球从某一高度落下(整数,单位米),每次落地后反跳回原来高度的一半,再落下. 编程计算气球在第10次落地时,共经过 ...

  2. pathlib路径问题

    下面是我的文件框架 app ------ file1---- .py1 file2---- .py2 config.py 我在config文件中设置了变量参数 BASE_DIR = pathlib.P ...

  3. HCNP Routing&Switching之IP安全

    前文我们了解了DHCP安全相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16637627.html:今天我们来聊一聊IP安全相关话题: 技术背景 随着 ...

  4. Linux_etc-passwd文件总结

    文件内容 ## # User Database # # Note that this file is consulted directly only when the system is runnin ...

  5. 【HMS Core】集成地图服务不显示地图问题

    ​[问题描述] 关于华为HMS-地图服务不显示地图的问题. 背景:集成华为地图服务运行后页面不显示地图,运行app后不展示地图报错MapsInitializer is not initialized. ...

  6. LVGL 入门使用教程

    一.准备资料 开发板:ESP32-S3 开发环境:VS Code + PlatformIO 串口屏驱动 TFT-eSPI:https://github.com/Bodmer/TFT_eSPI 触摸驱动 ...

  7. 第六章:Django 综合篇 - 3:使用MySQL数据库

    在实际生产环境,Django是不可能使用SQLite这种轻量级的基于文件的数据库作为生产数据库.一般较多的会选择MySQL. 下面介绍一下如何在Django中使用MySQL数据库. 一.安装MySQL ...

  8. 在CentOS 8服务器上搭建FastDFS环境

    什么是FastDFS? 这里,我就摘录下百度百科上对于FastDFS的描述. FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下 ...

  9. C#-12 转换

    一 什么是转换 转换是接受一个类型的值并使用它作为另一个类型的等价值的过程. 下列代码演示了将1个short类型的值强制转换成byte类型的值. short var1 = 5; byte var2 = ...

  10. 鼠标悬停过度事件:Transition

    CSS代码:<style> div{width:100px;height:100px;background:blue;transition: 0.5s;//0.5秒完成}div:hover ...