简介
- 简介
- get 和 post 的区别
- 是什么驱动了http 协议的变革
- http1.0
- http1.1
- cookie 和 header
- http2
- https
- http1.1 http2 https之间的关系
超文本传输协议,这决定了协议传输的内容。
如果你想了解一个http协议,就用一门语言基于socket包写一个特定的响应,然后基于浏览器访问它。
get 和 post 的区别
2018.05.11 补充
- GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。这个可以说出来十几条。
- 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。当然,这并不是强约束,firefox对post 就还只是发了一次。
是什么驱动了http 协议的变革
- 对于同一个域名,浏览器限制只能开6~8多个连接 ==> 连接复用
- 复杂,现在的页面,一个页面上有几十个资源文件是很常见的事儿 ==> 并行请求,请求压缩
- 安全
- 服务器推送,服务器在客户端没有请求的情况下主动向客户端推送消息。
http1.0
基本特点是“一来一回”:客户端发起一个TCP连接,在连接上发一个http request 到服务器,服务器返回一个http response,然后连接关闭。
主要有两个问题
- 性能问题,连接的建立、关闭都是耗时操作。为此设计了Keep-Alive机制实现Tcp连接的复用。
- 服务器推送问题
http1.1
一些改进:
- Keep-Alive 成为默认
- 支持Chunk 机制
问题:
- 在上一个请求的响应没有收到之前,无法发送下一个请求。学名pipeline,reids 因为服务端是单线程结构,所以支持pipeline
- 服务器推送问题
实现一个简单的http server
基于node.js socket写一个简单的http server
require('net').createServer(function(sock) {
sock.on('data', function(data) {
sock.write('HTTP/1.1 200 OK\r\n');
sock.write('\r\n');
sock.write('hello world!');
sock.destroy();
});
}).listen(9090, '127.0.0.1');
scala版本
object SocketServer {
def main(args: Array[String]): Unit = {
try {
val listener = new ServerSocket(8080);
val socket = listener.accept()
val data = "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nhello world!"
socket.getOutputStream.write(data.getBytes())
socket.close()
listener.close()
}
catch {
case e: IOException =>
System.err.println("Could not listen on port: 80.");
System.exit(-1)
}
}
}
long polling
http long-polling(推送),服务端故意不响应(一段时间),也不断连接。参见面试时如何优雅的谈论HTTP/1.0/1.1/2.0
Content-Type
Content-Type实体首部字段基本要点:
- Content-Type说明了http body的MIME类型的 header字段。
- MIME类型由一个主媒体类型(比如text,image,audio等)后面跟一条斜线以及一个子类型组成,子类型用于进一步描述媒体类型。
对于post请求,默认情况下, http 会对表单数据进行编码提交。笔者实现分片文件上传时,上传分片二进制数据,若是不指定Content-Type: application/octet-stream
则http对二进制进行了一定的变化,导致服务端和客户端对不上。
Content-Encoding
http协议中有 Content-Encoding(内容编码)。Content-Encoding 通常用于对实体内容进行压缩编码,目的是优化传输,例如用 gzip 压缩文本文件,能大幅减小体积。内容编码通常是选择性的,例如 jpg / png 这类文件一般不开启,因为图片格式已经是高度压缩过的。
内容编码针对的只是传输正文。在 HTTP/1 中,头部始终是以 ASCII 文本传输,没有经过任何压缩,这个问题在 HTTP/2 中得以解决。
Transfer-Encoding
Transfer-Encoding 用来改变报文格式。这涉及到一个通信协议的重要问题:如何定义协议数据的边界
- 发送完就断连接(非持久连接)
- 协议头部设定content-length
- 以特殊字符结尾
content-length有几个问题:
- 发送数据时,对某些场景,计算数据长度本身是一个比较耗时的事情,同时会占用一定的memory。
- 接收数据时,从协议头拿到数据长度,接收不够这个长度的数据,就不能解码后交给上层处理。
Transfer-Encoding 当下只有一个可选值:分块编码(chunked)。这时,报文中的实体需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。
require('net').createServer(function(sock) {
sock.on('data', function(data) {
sock.write('HTTP/1.1 200 OK\r\n');
sock.write('Transfer-Encoding: chunked\r\n');
sock.write('\r\n');
sock.write('b\r\n');
sock.write('01234567890\r\n');
sock.write('5\r\n');
sock.write('12345\r\n');
sock.write('0\r\n');
sock.write('\r\n');
});
}).listen(9090, '127.0.0.1');
server push
服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确地请求。
cookie 和 header
accept:image/webp,image/apng,image/*,*/*;q=0.8
accept-encoding:gzip, deflate, br
accept-language:en-US,en;q=0.9
cache-control:no-cache
cookie:GeoIP=US:CA:Los_Angeles:34.05:-118.26:v4; CP=H2; WMF-Last-Access=23-Feb-2018; WMF-Last-Access-Global=23-Feb-2018
cookie 是header的一种,cookie被浏览器自动添加,特殊处理
- 浏览器自动存储cookie,存储时按域名组织,并在发送请求时自动带上cookie(这导致某些数据不适合放在cookie中,因为会浪费网络流量)
- cookie既可以由服务端来设置(通过set-cookie header),也可以由客户端来设置(js
document.cookie = "name=Jonh; ";
)。 - HTTP cookieAn HTTP cookie is a small piece of data sent from a website and stored on the user’s computer by the user’s web browser while the user is browsing. Cookies were designed to be a reliable mechanism for websites to remember stateful information。The term “cookie” was coined by web browser programmer Lou Montulli. cookie 由一个 browser programmer 提出,由browser存储,目的是为了存储用户的状态信息。
对笔者个人来说,有以下几点要矫正:
-
header 分为
- 通用header,比如Date
- 请求特有header,比如Accept、Authorization、Cookie
- 响应特有header,比如Server、Set-Cookie
- body相关header,比如Content-Type
- 自定义header
因为springmvc 等framework,开发时不需要了解header,但framework确实进行了必要的设置
-
对于服务端开发,我们比较熟悉,将用户数据保存在数据库中,通过http请求改变用户记录的状态。其实,反向的过程也是支持的,常用的本地存储——cookie篇,随着浏览器的处理能力不断增强,越来越多的网站开始考虑将数据存储在「客户端」,提供了许多本地存储的手段。浏览器提供数据存储能力,服务器通过http响应来更改用户记录的状态。
http2
http1.1 和 http2 并不是出于平级的位置,而是处在http1.1 和 tcp之间。以前http1.1 是直接构建在tcp之上,现在相当于在http1.1 和tcp 之间多了一个转换层,也就是现在http2
二进制分帧 ==> 支持请求pipeline
http1.1 是明文的字符格式,所谓二进制分帧,是指把这个字符格式的报文给tcp 之前转换为二进制,并且分为多个帧frame 来发送。frame 是被乱序发出去的,到server 端被重新组装。 有两个问题
- 配对:请求和响应如何一一对应?
- 组装:请求被打散为frame,如何再组装到一起?
原理就是提出一个逻辑上的流的概念Stream(对应每个请求和响应),为每个Stream 分配一个ID,并打到每一个frame 上。
https
来自《http权威指南》
对web服务器发起请求时,我们需要一种方式来告知web服务器去执行http的安全协议版本,这是通过url中设定http或https来实现的。
- 如果是http,客户端就会打开一条到服务器80端口的连接
- 如果是https,客户端就会打开一条到服务器443端口的连接,一旦建立连接,client和server就会初始化ssl layer,对加密参数进行沟通,并交换密钥。ssl握手(SSLHandshake)完成之后,ssl layer初始化完成了。剩下的就是,browser将数据从http layer发到tcp layer之前,要经过ssl layer加密。
Java 和 HTTP 的那些事(四) HTTPS 和 证书