一篇关于 HTTP 和 TCP 协议及其区别和连接的文章。
引言
本文从以下几个方面走进 GET 与 POST 的区别:
- w3school 给出的标准答案
- 从 HTTP 是什么开始,深入 GET 与 POST 请求方法,即两者的本质区别
- 常见的 GET 与 POST 误解
- POST 方法比 GET 方法安全?
- POST 方法会产生两个 TCP 数据包?
标准答案
GET 与 POST 是 HTTP 请求中最常用的两种方法,GET 与 POST 的区别也是老生常谈的问题了,信手拈来
GET | POST | |
---|---|---|
后退按钮/刷新 | 无害 | 数据会被重新提交(浏览器应该告知用户数据会被重新提交)。 |
书签 | 可收藏为书签 | 不可收藏为书签 |
缓存 | 能被缓存 | 不能缓存 |
编码类型 | application/x-www-form-urlencoded | application/x-www-form-urlencoded 或 multipart/form-data。为二进制数据使用多重编码。 |
历史 | 参数保留在浏览器历史中。 | 参数不会保存在浏览器历史中。 |
对数据长度的限制 | 是的。当发送数据时,GET 方法向 URL 添加数据;URL 的长度是受限制的(URL 的最大长度是 2048 个字符)。 | 无限制。 |
对数据类型的限制 | 只允许 ASCII 字符。 | 没有限制。也允许二进制数据。 |
安全性 | 与 POST 相比,GET 的安全性较差,因为所发送的数据是 URL 的一部分。在发送密码或其他敏感信息时绝不要使用 GET ! | POST 比 GET 更安全,因为参数不会被保存在浏览器历史或 web 服务器日志中。 |
可见性 | 数据在 URL 中对所有人都是可见的。 | 数据不会显示在 URL 中。 |
上面是 w3school 给出的标准答案
但你真的理解它吗?在我们学习了那么多 HTTP 知识后,仅仅回答这些就够了吗?GET 与 POST 都是 HTTP 的请求方法,如何理解请求方法?本质区别又是什么?
下面让我们一步步走进 GET 与 POST 方法,以及两者的本质区别
深入 GET 与 POST 请求方法
1. HTTP 是什么?
HTTP (HyperText Transfer Protocol)是建立在 TCP 上的应用层协议,超文本传输协议。其中:
- 超文本:图片、音频、视频、甚至是压缩包等
- 传输:两点之间数据的双向传送
- 协议:一种行为约定和规范
所以,HTTP 协议用更通俗易懂的话描述就是 一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范
虽说 HTTP 协议是“传输协议”,但它不关心寻址、路由、数据完整性等传输细节,这些底层的具体传输工作是由 TCP/IP 协议负责,例如 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输,另外还有 DNS 协议实现域名查找、SSL/TLS 协议实现安全通信等
那 HTTP 协议主要干嘛喃?
2. HTTP 报文
HTTP 协议的核心部分就是它定义的传输报文的格式,例如报文的组成、解析规则等,以便于在 TCP/IP 上实现更多样灵活的功能,如缓存控制、数据编码、内容协议等
HTTP 报文分为四部分:
- 起始行:在请求报文中是请求行,在响应报文中是状态行(表示服务器的响应状态)
- 头部:header
- 空行:在 header 与 body 之间其实是有个 “空行” 的
- 实体:我们通常说的 body
注意:此报文中最后是一个空白行结束,没有 body(GET 请求一般都没有 body)
其中,请求方法就规定在起始行中:
- 请求行:GET /uri HTTP/1.1,包含请求方法 GET 或 POST 等
- 状态行:HTTP/1.1 200 OK,仅仅包含服务器的响应状态,不包含请求方法
请求方法
客户端发起 HTTP 请求,服务器响应客户端请求,客户端可以对服务器端的资源进行操作,例如查询、添加、删除等,但具体执行哪种操作喃?
这就是请求方法存在的意义,它规定了客户端的某种操作指令,用来告诉服务器端我需要进行哪种操作,常见的请求方法有:
- GET :获取资源,常用于读取或下载资源
- HEAD :请求一个与 GET 请求的响应相同的响应,只返回请求头,没有响应体,多数由 JavaScript 发起
- POST :用于将实体(body)提交到指定的资源,通常导致状态或服务器上的副作用的更改
- PUT :用请求有效载荷替换目标资源的所有当前表示。
- DELETE :删除指定的资源。
- CONNECT :建立一个到由目标资源标识的服务器的隧道,多用于 HTTPS 和 WebSocket 。
- OPTIONS :预检,用于描述目标资源的通信选项。通过该请求来知道服务端是否允许跨域请求。
- TRACE :沿着到目标资源的路径执行一个消息环回测试,多数线上服务都不支持
- PATCH :用于对资源应用部分修改。
GET 请求方法应该是 HTTP 所有请求方法中最开始出现的了,它表示从服务器获取资源
POST 请求方法是 HTTP 所有协议中除 GET 之外最常使用的请求方法了,它表示向指定的服务器资源提交数据,提交数据存放在 HTTP 报文中的 body 中,通常导致状态或服务器上的副作用的更改
3. GET 与 POST 请求方法的本质区别
综上所述,总结一下,GET 与 POST 的本质区别有两点:
- 请求行不同:
- GET:GET /uri HTTP/1.1
- POST:POST /uri HTTP/1.1
- 对服务器资源的操作不同:
- GET:表示从服务器获取资源
- POST:向指定的服务器资源提交数据(通常导致状态或服务器上的副作用的更改)
进阶:常见问题及解答
1. POST 方法比 GET 方法安全?
在 HTTP 协议里,所谓的“安全”是指请求方法不会对服务器上的资源进行修改,“破坏”服务器上的资源
按照这种定义,GET 请求方法是安全的,它对服务器资源执行的仅仅是只读操作,也是幂等的
幂等指多次执行相同的操作,结果也都是相同的,即多次“幂”后结果“相等”
POST 请求方法是不安全的,它会修改服务器上的资源,在 RFC 里的语义,POST 是指“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的
总结:
- GET:安全,幂等
- POST:不安全,不幂等
对于传输来说,GET 和 POST 报文在传输上都是不安全的,因为 HTTP 在网络上是明文传输的,想要安全传输就得加密,也就是 HTTPS
2. POST 方法会产生两个 TCP 数据包?
这个就神奇了,在部分文章中提到,POST 请求方法会将 header 和 body 分开发送,先发送 header,服务端返回 100 状态码再发送 body ????️????️????️
HTTP 协议中没有明确说明 POST 会产生两个 TCP 数据包,而且实际测试(Chrome、Firefox)发现,header 和 body 不会分开发送。
但为什么有些作者会这样写喃?我查找了相关资料,终于发现,真有这种情况,原文在这里:
In search of performance - how we shaved 200ms off every POST request
gocardless.com/blog/in-sea…
主要内容是作者发现 POST 比 GET 多 200ms,然后深入研究,发现 ruby 的 net::HTTP 库,会将一个 http 请求拆分,先发送 header 部分。另外,由于没有设置 TCP_NODELY ,所以第一个包之后要等待 ack ,才发下一个包,导致了一个请求有 200ms 的延迟。
另外,关于 HTTP 100 Continue:
100 Continue的目的是对HTTP客户端应用程序有一个实体的主体部分要发送服务器,但希望在发送之前查看一下服务器是否会接受这个实体这种情况进行优化
----《HTTP权威指南》
客户端:
如果客户端在向服务器发送一个实体,并愿意在发送实体之前等待100 Continue响应,那么客户端就要发送一个携带了值为100 Continue的Expect请求首部。如果客户端没有发送实体,就不应该发送100 Continue Expect首部,因为这样会使服务器误以为客户端要发送一个实体
服务器端:
如果服务器收到一条带有值为100 Continue的Expect首部的请求,它会用100 Continue响应或一条错误码来进行响应。服务器永远也不应该向没有发送100 Continue期望的客户端发送100 Continue状态码。
如果服务器在有机会发送100 Continue响应之前就收到了部分(或者全部)的实体,说明服务器已经打算继续发送数据了,这样服务器就不需要发送这个状态码了,但是服务器完成请求之后,还是应该为请求发送一个最终状态码
也就是说,没收到客户端的 100 Continue 就不会有响应
总结
因此,大多数框架都是尽量在一个 TCP 包里面把 HTTP 请求发出去的,但是也确实存在先发 HTTP 头,然后发 body 的框架。但是具体发多少个TCP包,这个 不是 HTTP 协议的事情是操作系统 TCP 协议栈与代码的问题,跟 HTTP 没关系
每天三分钟,进阶一个前端小 tip 面试题库 算法题库
上一篇: ABB HESG441634R1/K 具有极高的运行可靠性。
下一篇: [科学]工业互联网通信协议
推荐阅读
-
长连接和短连接、HTTP和TCP的Keep-Alive区别解析
-
go语言Socket编程-Socket编程 什么是Socket Socket,英文含义是插座、插孔,一般称之为套接字,用于描述IP地址和端口。可以实现不同程序间的数据通信。 Socket起源于Unix,而Unix基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。Socket就是该模式的一个实现,网络的Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用:Socket,该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。 套接字的内核实现较为复杂,不宜在学习初期深入学习,了解到如下结构足矣。 套接字通讯原理示意 在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识网络通讯中的一个进程。“IP地址+端口号”就对应一个socket。欲建立连接的两个进程各自有一个socket来标识,那么这两个socket组成的socket pair就唯一标识一个连接。因此可以用Socket来描述网络连接的一对一关系。 常用的Socket类型有两种:流式Socket(SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。 网络应用程序设计模式 C/S模式 传统的网络应用设计模式,客户机(client)/服务器(server)模式。需要在通讯两端各自部署客户机和服务器来完成数据通信。 B/S模式 浏览器(Browser)/服务器(Server)模式。只需在一端部署服务器,而另外一端使用每台PC都默认配置的浏览器即可完成数据的传输。 优缺点 对于C/S模式来说,其优点明显。客户端位于目标主机上可以保证性能,将数据缓存至客户端本地,从而提高数据传输效率。且,一般来说客户端和服务器程序由一个开发团队创作,所以他们之间所采用的协议相对灵活。可以在标准协议的基础上根据需求裁剪及定制。例如,腾讯所采用的通信协议,即为ftp协议的修改剪裁版。 因此,传统的网络应用程序及较大型的网络应用程序都首选C/S模式进行开发。如,知名的网络游戏魔兽世界。3D画面,数据量庞大,使用C/S模式可以提前在本地进行大量数据的缓存处理,从而提高观感。 C/S模式的缺点也较突出。由于客户端和服务器都需要有一个开发团队来完成开发。工作量将成倍提升,开发周期较长。另外,从用户角度出发,需要将客户端安插至用户主机上,对用户主机的安全性构成威胁。这也是很多用户不愿使用C/S模式应用程序的重要原因。 B/S模式相比C/S模式而言,由于它没有独立的客户端,使用标准浏览器作为客户端,其工作开发量较小。只需开发服务器端即可。另外由于其采用浏览器显示数据,因此移植性非常好,不受平台限制。如早期的偷菜游戏,在各个平台上都可以完美运行。 B/S模式的缺点也较明显。由于使用第三方浏览器,因此网络应用支持受限。另外,没有客户端放到对方主机上,缓存数据不尽如人意,从而传输数据量受到限制。应用的观感大打折扣。第三,必须与浏览器一样,采用标准http协议进行通信,协议选择不灵活。 因此在开发过程中,模式的选择由上述各自的特点决定。根据实际需求选择应用程序设计模式。 简单的C/S模型通信 Server端:Listen函数 func Listen(network, address string) (Listener, error) network:选用的协议:TCP、UDP, 如:“tcp”或 “udp” address:IP地址+端口号, 如:“127.0.0.1:8000”或 “:8000” Listener 接口: type Listener interface { Accept (Conn, error) Close error Addr Addr } Conn 接口: type Conn interface { Read(b byte) (n int, err error) Write(b byte) (n int, err error) Close error LocalAddr Addr RemoteAddr Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error } 参看 [<u>https://studygolang.com/pkgdoc</u>](https://studygolang.com/pkgdoc) 中文帮助文档中的demo: 示例代码:TCP服务器.go package main import ( "net" "fmt" ) func main { // 创建监听 listener, err:= net.Listen("tcp", ":8000") if err != nil { fmt.Println("listen err:", err) return } defer listener.Close // 主协程结束时,关闭listener fmt.Println("服务器等待客户端建立连接...") // 等待客户端连接请求 conn, err := listener.Accept if err != nil { fmt.Println("accept err:", err) return } defer conn.Close // 使用结束,断开与客户端链接 fmt.Println("客户端与服务器连接建立成功...") // 接收客户端数据 buf := make(byte, 1024) // 创建1024大小的缓冲区,用于read n, err := conn.Read(buf) if err != nil { fmt.Println("read err:", err) return } fmt.Println("服务器读到:", string(buf[:n])) // 读多少,打印多少。 }
-
隐私计算技术详解 | 一篇关于 SealPIR 的文章 - 基于同态的隐私信息检索协议 - 1. 隐私信息检索协议的定义和分类
-
一篇关于 HTTP 和 TCP 协议及其区别和连接的文章。
-
让我们在周末分享一篇关于 html 和 http 的文章吧
-
深入了解 TCP 协议及其源代码--"三次握手 "背后的连接和绑定、监听、接受。
-
玩转Java底层:JMX详解 - jconsole与自定义MBean监控工具的实际应用与区别" 在日常JVM调优中,我们熟知的jconsole工具通过JMX包装的bean以图形化形式展示管理数据,而像jstat和jmap这类内建监控工具则由JVM直接支持。本文将以jconsole为例,深入讲解其实质——基于JMX的MBean功能,包括可视化界面上的bean属性查看和操作调用。 MBeans在jconsole中的体现是那些可观察的组件属性和方法,如上图所示,通过名为"Verbose"的属性能看到其值为false,同时还能直接操作该bean的方法,例如"closeJerryMBean"。 尽管jconsole给我们提供了直观的可视化界面,但请注意,这里的MBean并非固定不变,开发者可根据JMX提供的接口将自己的自定义bean展示到jconsole。以下步骤展示了如何创建并注册一个名为"StudyJavaMBean"的自定义MBean: 1. 首先定义接口`StudyJavaMBean`,接口需遵循MBean规范,即后缀为"MBean"且包含getter方法代表属性,如`getApplicationName`,和无返回值的setter方法代表操作,如`closeJerryMBean`。 ```java public interface StudyJavaMBean { String getApplicationName(); void closeJerryMBean(); } ``` 2. 编写接口的实现类`StudyJavaMBeanImpl`,实现接口中的方法: ```java public class StudyJavaMBeanImpl implements StudyJavaMBean { @Override public String getApplicationName() { return "每天学Java"; } @Override public void closeJerryMBean() { System.out.println("关闭Jerry应用"); } } ``` 3. 在代码中注册自定义MBean,涉及的关键步骤包括: - 获取平台MBeanServer - 定义ObjectName,指定唯一的MBean标识符 - 注册MBean到服务器 - 启动RMI连接器服务,以便jconsole能够访问 ```java public void registerMBean() throws Exception { // ... 具体实现省略 ... } ``` 实际运行注册后的MBean,您将在jconsole中发现并查看自定义bean的属性和调用相关方法。然而,这种方式相较于传统的属性/日志查看和HTTP接口,实用性相对有限,可能存在潜在的安全风险。但不可否认的是,JMX及其MBean机制对于获取操作系统信息、内存状态等关键性能指标仍然具有重要价值。例如: 1. **获取操作系统信息**:通过JMX MBean,可以直接获取到诸如CPU使用率、操作系统版本等系统级信息,这对于资源管理和优化工作具有显著帮助。
-
《编译原理》:理解终结符与非终结符的判断方法与技巧 重新表述: 本文将向你介绍《编译原理》中关于终结符与非终结符的相关概念及其应用。 首先,我们将解释什么是终结符和非终结符,并通过具体的例子来帮助你更好地理解它们的区别和联系。 其次,我们还会分享一些实用的方法和技巧,以便你在学习和实践过程中更加高效地运用这些概念。 最后,我们将会讨论如何通过识别符号开始,逐步将非终结符替换为相应的规则右部的符号串,最终得到一个只包含终结符的句子。 希望这篇文章能对你有所帮助,让你在学习编译原理的过程中取得更好的进展。