设为首页 加入收藏

TOP

[Computer Networks]一个http请求的完成的全过程(一)
2023-07-23 13:32:57 】 浏览:67
Tags:Computer Networks 一个 http 成的全

摘要

本文主要讲述了一个 http request 请求从发出到收到 response 的整个生命周期,希望可以通过对整个流程的一个描述来梳理清楚五层网络协议的定义以及各层之间是如何协作的。

使用Golang发起一个HTTP请求

对于后端来说通过 http 请求来进行远程调用是再寻常不过的事了,以 Golang 的 resty 包为例,我们通过下面这个语句来发起一个请求并获得所请求的服务器的 response,简单起见这里我们使用 GET 方法进行请求:

client := resty.New()
headers := map[string]string{
	"Connection": "Keep-Alive",
}
resp1, _ := client.R().
	EnableTrace().
	SetHeaders(headers).
	Get("https://httpbin.org/get")

fmt.Println("Request Trace Info:")
ti := resp1.Request.TraceInfo()
fmt.Println("  DNSLookup     :", ti.DNSLookup)
fmt.Println("  TCPConnTime   :", ti.TCPConnTime)
fmt.Println("  TLSHandshake  :", ti.TLSHandshake)
fmt.Println("  IsConnReused  :", ti.IsConnReused)
fmt.Println("  RemoteAddr    :", ti.RemoteAddr.String())

我们在应用层发起请求,应用层是用户的,所以 HTTP 报文的内容都是一些人类可阅读的 ASCII 码点,但计算机只懂得二进制,光纤中认识光信号,所以这个 HTTP 报文还需要经过一一些处理才能穿越那些物理链路发送到我们的目的服务器上。首先来讲讲 HTTP 报文格式
image

在我们这个例子里我们的请求方法是 GET,GET 和 POST 是最常见的 HTTP 方法,除此以外还包括 DELETE、HEAD、OPTIONS、PUT、TRACE。我们没有传头部字段,也就是 HEADER , HTTP 的头部可以分为两种,一种是通用头部如 Cache-Control、 Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via 等,可以通过它传递一些信息,对通用头部的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头部,一般将会作为实体头部处理。实体头域包含关于实体的原信息,实体头包括 Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。extension-header 允许客户端定义新的实体头,但是这些域可能无法为接受方识别。
在这个请求里我们也没有消息体,URL为 https://httpbin.org/get, 是一个很简单的 GET 请求。
http 响应报文结构和请求差不多,区别在于状态行,状态码(Status-Code)主要用于机器理解,短语(Reason-Phrase)Status-Code 提供一个简单的文本描述,主要帮助用户理解:

  • 1xx : 信息响应类,表示接收到请求并且继续处理
  • 2xx : 处理成功响应类,表示动作被成功接收、理解和接受
  • 3xx : 重定向响应类,为了完成指定的动作,必须接受进一步处理
  • 4xx : 客户端错误,客户请求包含语法错误或者是不能正确执行
  • 5xx : 服务端错误,服务器不能正确执行一个正确的请求

几个常见的状态码和短语:

  • 200 OK 最好的情况,即处理成功
  • 404 Not Found 不希望看到的响应之一,即找不到所请求的资源
  • 500 Internal Server Error 不希望看到的响应之二,服务端发生了错误

说完了 HTTP 报文,接下来我们来实践一下,看看上面那段代码发起一个 HTTP 请求,它的运行结果如下:
image

可以看到我们这个请求是成功了的,对方服务器返回了 200, 短语是 OK,意味着目标服务器成功处理了我们的请求。
输出的Request Trace Info信息可以帮助我们理解整个请求的过程,我们一行一行地看:

DNSLookup

HTTP 报文里包含了目的服务器的地址,也就是我们上面输入的 URL,一个 URL 由协议头(HTTP、HTTPS、SFTP 等)+ 域名 + 资源路径组成,在我们这个例子里协议头为https(HTTPS = HTTP + SSL(TLS),它和 HTTP 的区别在于加了一道身份验证所以更安全),域名是 httpbin.org ,资源路径是 /get,也就是我们以 HTTPS 协议所约定的方式去获取 httpbin.org 所映射的服务器上的 /get 路径下的资源。
域名由字符串组成,机器是无法读懂的,所以我们需要一个服务去将它解析成机器能读懂的地址,也就是 IP,而这个服务就是 DNS(Domain Name System)域名系统,它是用于实现域名和IP地址相互映射的一个分布式数据库,这里输出的 DNSLookup 的值就是本次请求里花费在 DNS 解析上的时间。
域名解析的过程大致如下:
image
完整的DNS解析过程有以下几个步骤:
(1)查看浏览器缓存(我们这里是直接通过后端来发起请求,所以没有这一步)
当用户通过浏览器访问某域名时,浏览器首先会在自己的缓存中查找是否有该域名对应的 IP 地址(若曾经访问过该域名且没有清空缓存便存在)。
(2)查看系统缓存
当浏览器缓存中无域名对应 IP 则会自动检查用户计算机系统 Hosts 文件 DNS 缓存是否有该域名对应 IP。
(3)查看路由器缓存
当浏览器及系统缓存中均无域名对应 IP 则进入路由器缓存中检查,以上三步均为客服端的 DNS 缓存。
(4)查看ISP DNS 缓存
当在用户客服端查找不到域名对应 IP 地址,则将进入 ISP DNS 缓存中进行查询。比如你用的是电信的网络,则会进入电信的 DNS 缓存服务器中进行查找。
(5)询问根域名服务器
当以上均未完成,则进入根服务器进行查询。全球仅有 13 台根域名服务器,1 个主根域名服务器,其余 12 为辅根域名服务器。根域名收到请求后会查看区域文件记录,若无则将其管辖范围内顶级域名(如.com、.cn等)服务器 IP 告诉本地 DNS 服务器。
(6)询问顶级域名服务器
顶级域名服务器收到请求后查看区域文件记录,若无记录则将其管辖范围内权威域名服务器的 IP 地址告诉本地 DNS 服务器。
(7)询问权威域名(主域名)服务器
权威域名服务器接受到请求后查询自己的缓存,如果没有则进入下一级域名服务器进行查找,并重复该步骤直至找到正确记录。
(8)保存结果至缓存
本地域名服务器把返回的结果保存到缓存,以备下一次使用,同时将该结果反馈给客户端,客户端通过这个 IP 地址即可访问目标Web服务器。至此,DNS 递归查询的整个过程结束。

首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇浅谈一下go语言中的slice及其一些.. 下一篇如何站在开发者的角度理解框架的..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目