前言:
文章预计分为四个部分逐步更新
2023-04-13 星期四 一更 全文共计约 3800 字 阅读大约花费 5 分钟
文章目录:
- Web 的工作方式
- 用 Go 搭建一个最简单的 Web 服务
- 了解 Golang 运行 web 的原理
- Golang http 包详解(源码剖析)
- 总结
正文:
Web 的工作方式
了解当你访问一个网页时,背后是如何运作的,发生了一些什么?
客户端 的角色,首先你的浏览器会去请求 DNS 服务器进行域名解析,将你输入的 URL 地址 转化为对应的 ip 地址,通过 ip 地址 我们就可以找到对应的服务器位置,从而进行 TCP 连接。
客户端收到了来自服务端的响应之后开始渲染这个响应包里的主体(body),等收到了全部的内容应答后,就会断开与服务器的 TCP 连接 (这里先讨论一般情况)
如图👇
所以 Web 服务器的工作原理可以简单的总结为:
- 客户端通过 TCP/IP 协议建立与服务器的 TCP 连接
- 客户端向服务器发送 HTTP 协议请求包,请求服务器里的资源文档
- 服务器向客户机发送 HTTP 协议应答包,如果请求的资源包含有其他动态语言的内容,服务器就会调用动态语言的解析引擎负责处理这些动态内容,并将处理得到的数据返回给客户端
- 客户端与服务端断开连接。客户端开始解释收到的 HTML 文档,在客户端屏幕上渲染图形结果
URL 和 DNS 解析
刚刚我们提到了 URL,它可以用来输入访问网页,那具体 URL 是个什么东西呢?URL 是 Uniform Resource Locator“统一资源定位符” 的英文缩写
基本格式如下图👇
Domain Name System “域名系统” 的英文缩写,它是一种组织成 域层次结构的计算机和网络服务命名系统,它用于 TCP/IP 网络,它从事 将主机名 或者 域名转换为实际 IP 地址的工作。可以把他理解成 URL 的“翻译官”
- 我们以 www.google.com 为例,在浏览器地址栏输入该域名,操作系统会首先检查自己的 hosts 文件中是否存在这个网址的映射关系,如果有,就可以直接调用这个 IP 地址的映射,完成域名解析
- 其次如果 hosts 里没有这个域名的映射,则查找本地 DNS 解析器缓存,看里面有没有这个网址的映射关系,如果有也直接调用
- 如果 hosts 和 本地 DNS 解析器缓存都没有,就会先去找 TCP/IP 参数中设置的首选 DNS 服务器,我们可以把他叫做 本地 DNS 服务器,此服务器收到查询需求时,如果要查询的域名,包含在本地配置区域的资源中,就将解析结果返回给客户端,完成域名解析,该解析具有权威性
- 如果要查询的域名,本地 DNS 服务器配置区域资源没有,但是该服务器却缓存了此网址的映射关系,则也可以调用完成解析,但是该解析不具有权威性
- 如果本地 DNS 服务器本地区域资源文件以及缓存都没有该映射,则根据本地 DNS 服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS 就把请求发送至 “根 DNS 服务器” ,“根 DNS 服务器”收到请求后会判断这个域名是谁来授权管理(本例子为.com),并会返回一个负责该顶级域名服务器的一个 IP。本地 DNS 服务器 收到 IP 信息后,将会联系 负责管理 .com 域的这台服务器。这台服务器收到请求后,如果自己无法解析,它就会找管理 .com 域的下一级 DNS 服务器地址(这里是 google.com)并把它的 IP 给本地 DNS 服务器。当本地 DNS 服务器收到这个地址后,就会找 google.com 域服务器,重复上面的操作,进行查询,直到找到(www.goole,com)为止
- 如果是转发模式,则此 DNS 服务器就会把请求转发至上一级 DNS 服务器,由上一级服务器进行解析,上一级如果不能解析,就找根服务器,或者转发请求给上上级服务器,如此循环,直到找到(www.goole,com)为止
无论是转发模式还是非转发模式,是转发给上一级还是直接找根 DNS,最后都是把 结果返回给 本地 DNS 服务器,由此 DNS服务器再返回给 我们的浏览器(客户端)
HTTP 协议详解
HTTP 协议当然是 Web 服务器工作的核心,所以我们接下来具体详细地了解清楚一下 HTTP 协议是怎么发挥作用的
-
事务。而服务器不能主动去与客户端联系,也不能给客户端发出一个回调连接,只能被动监听。
-
HTTP 协议是无状态的,同一个客户端的这一次请求与上次请求之间没有对应关系,对 HTTP 服务器来说,它并不知道这两个请求是否来自同一个客户端。当然对于需要解决这个问题的情况我们可以使用 "Cookie"机制来维护连接的可持续状态
“请求-响应协议” 即 客户端发出请求,服务端收到请求返回响应。
接下来我们分别看看 HTTP 协议的 请求包和响应包
HTTP 请求包 (浏览器/客户端 信息)
Request 包分为三部分,第一部分叫 Request line (请求行),第二部分是 Request header (请求头),第三部分是 body(主体),header 和 body 之间会有个空行隔开
请求包的实例图👇
这四个操作中最熟悉和常用的是 GET 和 POST 。
GET 一般用于获取/查询资源信息
POST 一般用于更新资源信息
GET 与 POST 的区别:
- GET 方法提交的数据会放在 URL 后面,使用 ? 分割 URL 和 传输的数据,参数之间以 & 相连
- POST 方法则是把提交的数据放在 HTTP 包的 body 中
- GET能提交的数据大小会因为浏览器对于 URL 的长度限制而有所限制
- POST 方法提交的数据不会有限制
- GET 方法提交数据会带来某些安全问题,例如:在用户的登录界面,如果使用 GET 方法提交数据,用户的账号和密码就会出现在 URL 上面,如果页面被缓存或者其他人可以访问机器,就可以额从历史记录中获得该用户的账号和密码!
GET 和 POST 到底有什么区别?
HTTP 响应包(服务器信息)
”状态行“,由 HTTP 协议版本号、状态码、状态消息 三部分组成
状态码的作用是告诉 HTTP 客户端(浏览器),HTTP 服务器是否产生了预期的 Response。
在 HTTP 1.1 协议中定义了 5 类 状态码,每个状态码由三位数字组成,首位表示类别:
- 1xx 提示信息:表示请求被成功接受,继续处理
- 2xx 成功:表示请求已被成功接受
- 3xx 重定向:表示要完成这个请求必须进行更进一步的处理
- 4xx 客户端错误:客户端的语法错误或者请求无法实现
- 5xx 服务端错误:服务器未能实现合法的请求
Tips: 持续连接 与 非持续连接(协议无状态/keep-alive)
无状态是指协议对于事物处理没有记忆能力,服务器不知道客户端是什么状态,体现在打开一个服务器的网页和你之前打开这个服务器的网页之间没有任何联系
无状态不代表不能保持TCP连接(只要不断开连接我就不管你什么状态不状态的)
从 HTTP 1.1 开始,默认都开启了 叫做 Keep-Alive 的保持连接的特性,也就是当一个网页打开完成之后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的 TCP 连接
如果你尝试去检查(F12)访问任意一个网址
通过分析整个 URL 请求的通信过程,你会发现:
在所有的请求中不止一个 URL 请求,还会有很多其他的如静态文件的资源请求
这其实是浏览器自带的功能之一,第一次请求 url ,服务器端返回的是 HTML 页面,然后浏览器会开始渲染这个页面,但是当解析到 HTML DOM里面的图片连接、css脚本和js脚本的连接的时候,浏览器就会自动地发起一个请求静态资源的 HTTP 请求,去获取相应的资源并渲染,最终将所有资源整合完整地展现出来
总结
- 在这一部分,我们初步认识了 Web 的工作方式,并对一些基础的计算机网络相关知识有了进一步了解,特别是对于 基于 TCP 协议的 HTTP 协议,以及该协议如何在整个 客户端-服务端 中运作。
- 当我们知道了 Web 就是一个基于 HTTP 协议的的一个服务的时候,我们就可以做好准备,去尝试在 Go 语言中体会如何搭建一个可以运行的 Web 服务了。
关于 Golang 基础部分 以及 计算机网络部分读者可以参阅我的往期 blog👇
Goalng:基础复习一遍过
以上
看完记得留下一个👍