1 概述

1.1 Web工作方式

我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢?

对于普通的上网过程,系统其实是这样做的:浏览器本身是一个客户端,当你输入URL的时候,首先浏览器会去请求DNS服务器,通过DNS获取相应的域名对应的IP,然后通过IP地址找到IP对应的服务器后,要求建立TCP连接,等浏览器发送完HTTP Request(请求)包后,服务器接收到请求包之后才开始处理请求包,服务器调用自身服务,返回HTTP Response(响应)包;客户端收到来自服务器的响应后开始渲染这个Response包里的主体(body),等收到全部的内容随后断开与该服务器之间的TCP连接。

一个Web服务器也被称为HTTP服务器,它通过HTTP协议与客户端通信。这个客户端通常指的是Web浏览器(其实手机端客户端内部也是浏览器实现的)。

Web服务器的工作原理可以简单地归纳为:

  • 客户机通过TCP/IP协议建立到服务器的TCP连接
  • 客户端向服务器发送HTTP协议请求包,请求服务器里的资源文档
  • 服务器向客户机发送HTTP协议应答包,如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端
  • 客户机与服务器断开。由客户端解释HTML文档,在客户端屏幕上渲染图形结果

1.2 HTTP协议

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,它详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。

HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:

1.3 地址(URL)

URL全称为Unique Resource Location,用来表示网络资源,可以理解为网络文件路径。

URL的格式如下:

    http://host[":"port][abs_path]http://192.168.31.1/html/index

URL的长度有限制,不同的服务器的限制值不太相同,但是不能无限长。

2 HTTP报文浅析

2.1 请求报文格式

1) 测试代码

服务器测试代码:

package mainimport ("fmt""log""net"
)func main() {//创建、监听socketlistenner, err := net.Listen("tcp", "127.0.0.1:8000")if err != nil {log.Fatal(err) //log.Fatal()会产生panic}defer listenner.Close()conn, err := listenner.Accept() //阻塞等待客户端连接if err != nil {log.Println(err)return}defer conn.Close() //此函数结束时,关闭连接套接字//conn.RemoteAddr().String():连接客服端的网络地址ipAddr := conn.RemoteAddr().String()fmt.Println(ipAddr, "连接成功")buf := make([]byte, 4096) //缓冲区,用于接收客户端发送的数据//阻塞等待用户发送的数据n, err := conn.Read(buf) //n代码接收数据的长度if err != nil {fmt.Println(err)return}//切片截取,只截取有效数据result := buf[:n]fmt.Printf("接收到数据来自[%s]==>:\n%s\n", ipAddr, string(result))
}

浏览器输入url地址:

服务器端运行打印结果如下:

2) 请求报文格式说明

HTTP 请求报文由请求行、请求头部、空行、请求包体4个部分组成,如下图所示:

1)请求行
请求行由方法字段、URL 字段 和HTTP 协议版本字段 3 个部分组成,他们之间使用空格隔开。常用的 HTTP 请求方法有 GET、POST。

GET:

  • 当客户端要从服务器中读取某个资源时,使用GET 方法。GET 方法要求服务器将URL 定位的资源放在响应报文的数据部分,回送给客户端,即向服务器请求某个资源。
  • 使用GET方法时,请求参数和对应的值附加在 URL 后面,利用一个问号(“?”)代表URL 的结尾与请求参数的开始,传递参数长度受限制,因此GET方法不适合用于上传数据。
  • 通过GET方法来获取网页时,参数会显示在浏览器地址栏上,因此保密性很差。

POST:
- 当客户端给服务器提供信息较多时可以使用POST 方法,POST 方法向服务器提交数据,比如完成表单数据的提交,将数据提交给服务器处理。
- GET 一般用于获取/查询资源信息,POST 会附带用户数据,一般用于更新资源信息。POST 方法将请求参数封装在HTTP 请求数据中,而且长度没有限制,因为POST携带的数据,在HTTP的请求正文中,以名称/值的形式出现,可以传输大量数据。

2)请求头部
请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔。

请求头部通知服务器有关于客户端请求的信息,典型的请求头有:

请求头 含义
User-Agent 请求的浏览器类型
Accept 客户端可识别的响应内容类型列表,星号“ * ”用于按范围将类型分组,用“ / ”指示可接受全部类型,用“ type/* ”指示可接受 type 类型的所有子类型
Accept-Language 客户端可接受的自然语言
Accept-Encoding 客户端可接受的编码压缩格式
Accept-Charset 可接受的应答的字符集
Host 请求的主机名,允许多个域名同处一个IP 地址,即虚拟主机
connection 连接方式(close或keepalive)
Cookie 存储于客户端扩展字段,向同一域名的服务端发送属于该域的cookie

3)空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。

4)请求包体
请求包体不在GET方法中使用,而是POST方法中使用。
POST方法适用于需要客户填写表单的场合。与请求包体相关的最常使用的是包体类型Content-Type和包体长度Content-Length。

2.2 响应报文格式

1) 测试代码

服务器示例代码:

package mainimport ("fmt""net/http"
)//服务端编写的业务逻辑处理程序
func myHandler(w http.ResponseWriter, r *http.Request) {fmt.Fprintln(w, "hello world")
}func main() {http.HandleFunc("/go", myHandler)//在指定的地址进行监听,开启一个HTTPhttp.ListenAndServe("127.0.0.1:8000", nil)
}

启动服务器程序:

客户端测试示例代码:

package mainimport ("fmt""log""net"
)func main() {//客户端主动连接服务器conn, err := net.Dial("tcp", "127.0.0.1:8000")if err != nil {log.Fatal(err) //log.Fatal()会产生panicreturn}defer conn.Close() //关闭requestHeader := "GET /go HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, */*\r\nAccept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)\r\nAccept-Encoding: gzip, deflate\r\nHost: 127.0.0.1:8000\r\nConnection: Keep-Alive\r\n\r\n"//先发送请求包conn.Write([]byte(requestHeader))buf := make([]byte, 4096) //缓冲区//阻塞等待服务器回复的数据n, err := conn.Read(buf) //n代码接收数据的长度if err != nil {fmt.Println(err)return}//切片截取,只截取有效数据result := buf[:n]fmt.Printf("接收到数据[%d]:\n%s\n", n, string(result))
}

启动程序,测试http的成功响应报文:

启动程序,测试http的失败响应报文:

2) 响应报文格式说明

HTTP 响应报文由状态行、响应头部、空行、响应包体4个部分组成,如下图所示:

1)状态行
状态行由 HTTP 协议版本字段、状态码和状态码的描述文本3个部分组成,他们之间使用空格隔开。

状态码:
状态码由三位数字组成,第一位数字表示响应的类型,常用的状态码有五大类如下所示:

状态码 含义
1xx 表示服务器已接收了客户端请求,客户端可继续发送请求
2xx 表示服务器已成功接收到请求并进行处理
3xx 表示服务器要求客户端重定向
4xx 表示客户端的请求有非法内容
5xx 表示服务器未能正常处理客户端的请求而出现意外错误

常见的状态码举例:

状态码 含义
200 OK 客户端请求成功
400 Bad Request 请求报文有语法错误
401 Unauthorized 未授权
403 Forbidden 服务器拒绝服务
404 Not Found 请求的资源不存在
500 Internal Server Error 服务器内部错误
503 Server Unavailable 服务器临时不能处理客户端请求(稍后可能可以)

2)响应头部
响应头可能包括:

响应头 含义
Location Location响应报头域用于重定向接受者到一个新的位置
Server Server 响应报头域包含了服务器用来处理请求的软件信息及其版本
Vary 指示不可缓存的请求头列表
Connection 连接方式

3)空行
最后一个响应头部之后是一个空行,发送回车符和换行符,通知服务器以下不再有响应头部。

4)响应包体
服务器返回给客户端的文本信息。

3 参考资料

https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/03.1.md

Go基础编程:HTTP报文浅析相关推荐

  1. Linux应用程序设计之网络基础编程

    1.TCP/IP协议概述 1.1.OSI参考模型及TCP/IP参考模型 OSI协议参考模型是基于国际标准化组织(ISO)的建议发展起来的,从上到下工分为7层:应用层,表示层,会话层,传输层,网络层,数 ...

  2. ARM Cortex-M嵌入式C基础编程(下)

    ARM Cortex-M嵌入式C基础编程(下) ARM Cortex-M Embedded C Fundamentals/Tutorial-Aviral Mittal Load Region Vs E ...

  3. ARM Cortex-M嵌入式C基础编程(上)

    ARM Cortex-M嵌入式C基础编程(上) ARM Cortex-M Embedded C Fundamentals/Tutorial -Aviral Mittal 此技术是关于从编写简单的嵌入式 ...

  4. Go基础编程:作用域

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. Go基础编程:作用域11 小弟初学go语言,感觉作用域的运用还是很广泛的,所以就写上一点,也许有的都是很常见的,不过也没 ...

  5. 实验四 数据库SQL语言基础编程

    -- 实验四 数据库SQL语言基础编程 -- 实验目的: --  掌握数据库查询语句的编写方法 --  掌握利用查询语言完成基本查询 --  掌握利用SQL语句完成数据的添加.删除.修改操作 -- 实 ...

  6. PTA 基础编程题目集 6-6 求单链表结点的阶乘和

    PTA 基础编程题目集 6-6 求单链表结点的阶乘和 本题要求实现一个函数,求单链表L结点的阶乘和.这里默认所有结点的值非负,且题目保证结果在int范围内. 函数接口定义: int Factorial ...

  7. PTA 基础编程题目集 7-27 冒泡法排序 C语言

    PTA 基础编程题目集 7-27 冒泡法排序 C语言 将N个整数按从小到大排序的冒泡排序法是这样工作的:从头到尾比较相邻两个元素,如果前面的元素大于其紧随的后面元素,则交换它们.通过一遍扫描,则最后一 ...

  8. PTA 基础编程题目集 7-33 有理数加法 C语言

    PTA 基础编程题目集 7-33 有理数加法 C语言 本题要求编写程序,计算两个有理数的和. 输入格式: 输入在一行中按照a1/b1 a2/b2的格式给出两个分数形式的有理数,其中分子和分母全是整形范 ...

  9. PTA 基础编程题目集 7-24 约分最简分式 C语言

    PTA 基础编程题目集 7-24 约分最简分式 C语言 分数可以表示为分子/分母的形式.编写一个程序,要求用户输入一个分数,然后将其约分为最简分式.最简分式是指分子和分母不具有可以约分的成分了.如6/ ...

最新文章

  1. 【转】jQuery获取Select option 选择的Text和Value
  2. 【C++ 语言】引用 ( 引用简介 | 指针常量 | 常量指针 | 常引用 | 引用参数 | 引用 指针 对比 )
  3. h3c_rip附加相关视频
  4. IT经理世界:专注莫如史玉柱
  5. Android: 创建一个AlertDialog对话框,必须按确定或取消按钮才能关闭对话框,禁止按[返回键]或[搜索键]关闭
  6. 字符和编码之间的转换(Python)
  7. 玩转12306之系统登录
  8. python中ans的用法_python cx_Oracle基础使用方法
  9. Mac homebrew报错Error: homebrew-core is a shallow clone.
  10. gff文件_根据gff/gtf等注释文件取负链上的序列:先反向互补染色体再截取?还是先截取区间再反向互补序列?...
  11. 为Web Service添加缓存
  12. iframe在ie和firefox中的高度兼容性问题解决
  13. 做数据分析已经会Excel了,还要学Python吗?
  14. CSS从入门到精通——基础知识
  15. 剪贴板扩展windows_增强和扩展Windows剪贴板功能的最佳工具
  16. EXCEL转PDF后如何居中
  17. 微信语音技术原理_干货 | 2 分钟论文:语音生成表情包背后的技术原理
  18. 计算机网络安全 第二章 物理安全
  19. 产品方法论—如何竞品分析
  20. Camera ITS测试

热门文章

  1. java计算机毕业设计学习社区管理系统源码+数据库+系统+lw文档+部署
  2. 一文带你了解Web前端发展历程
  3. Java中的Properties属性集合
  4. 如何彻底删除Edge浏览器
  5. Microsoft Excel 直方图
  6. 日分析破亿!Stratifyd在AI数据分析领域再获佳绩
  7. ADS7844E模数转换器
  8. 公司项目中的biz层和manager层是干啥的
  9. vista正版序列号下载
  10. JAVA-打包成jar包