HTTP学习笔记

2020-03-23  本文已影响0人  前端艾希

1. HTTP发展史

HTTP/0.9 - 单行协议

http 0.9版本很简单,因为请求指令只由单行构成,所以被称之为单行协议,请求命令由:GET+url构成,例如:

GET /index.html

没有请求头等描述信息,服务器接收或者发送完数据后立马关闭TCP连接。

HTTP/1.0 - 构建可扩展性

增加了其他的请求方式,状态码,请求头等信息,增加了多字符集支持,多部分内容发送(发送多个文件时会对内容进行拆分),权限验证,缓存控制等功能。另外,在请求头的帮助下,http能够传输除了纯文本之外其他类型文档的能力。这时,一个典型的请求如下:

// request
GET /index.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)

//response
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html

HTTP/1.1 - 标准化的协议

1997年初,http 1.1标准发布,该标准消除了大量的歧义,并且引入了多项改进:

GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header

200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding

HTTP/2 - 为了更优异的表现

http 2主要解决了一些安全性问题和优化了管道复用技术,与之前的版本相比较:

TCP三次握手和四次挥手

因为http协议是应用层协议,是建立在tcp协议之上的,所以我们有必要了解下tcp连接的创建过程。

三次握手

假定 A为客户端,也就是请求的发起者,B为服务端,一次tcp建立的过程应该是:

// seq, ack(acknowledge,确认码) 均存在TCP报文的首部中,占4个字节,
// seq(sequence number,随机码) 是请求时随机生成的,
// syn = 1的意思是 syn(synchronous,建立码)这个标志放在了第一位

A (syn=1, seq=x)  ==> B
A  <== B (ack=x+1, syn=1, seq=y)
A (ack=y+1, seq=z)  ==> B

四次挥手

因为tcp连接是全双工的,所以断开连接时得双方都确认关闭,具体流程如下:

// fin(finish,结束码)

A (fin=m) ==> B
A <== B (ack=m+1)
A <== B (fin=n)
A (ack=n+1) ==> B

2. CORS和CORS预请求

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求
出于安全考虑,浏览器会限制从脚本内发起的跨域 http请求,例如xhrfetch,这意味着一个web应用程序只能加载来自同一个域的资源。

解决跨域的办法

解决跨域有很多种办法,例如jsonP,或者代理,但是这些和http协议并不相关,这里主要介绍如何配置headers来实现跨域。**跨域资源共享标准新增了一组http首部字段,可以声明允许跨域的源和方法等。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。

CORS预请求

简单请求不会触发预请求,对于简单请求,这里是这样定义的:

3. Cache-Control和验证头

重用已获取的资源能够有效的提升网站与应用的性能。Web 缓存能够减少延迟与网络阻塞,进而减少显示某个资源所用的时间。借助 HTTP 缓存,Web 站点变得更具有响应性。

Cache-Control头

这个头是服务器用来声明该资源的可缓存性的,它的值有以下几种情况:

缓存的生命周期

// node语法
response.writeHeader(200, {
  'Cache-Control': 'Max-Age=86400, public' // 设置有效期24小时,公共缓存
})

验证头信息

验证头一般出现在缓存方式为Cache-control: must-revalidate的情况下,因为该类资源可能会频繁改变,所以为了确保客户端的资源是具有时效性的,服务器会要求客户端在使用该缓存副本的时候向浏览器确认该缓存是否可用。

4. Cookie和Session

HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie使基于无状态的HTTP协议记录稳定的状态信息成为了可能。
我们一般在服务端设置Cookie,例如:

res.writeHeader(200,{
'Set-Cookie': ['token=123; max-age=10', 'name=bing; HttpOnly', 'id=123; domain=test.com'] // 多个cookie元素使用数组来表示(node js)
})

Node.js中我们一般通过数组来一次性设置多个Cookiemax-age=10表示该Cookie的有效时间为10s,如果不设置过期时间,浏览器会默认该Cookie的过期时间就是浏览器关闭的时间;HttpOnly表示该Cookie仅能被Http请求读取与使用,无法通过JavaScript读取,提供了一定的安全性保证;domain=test.com表示该Cookie所属的域是test.com,我们不能跨域访问Cookie;另外,如果我们想要达到这样的效果:同一个一级域名下的二级域名都可以访问到主域名的Cookie。那我们只需要在访问主域名的时候设置了Cookie,在访问二级域名的时候就可以获取Cookie了。另外补充一点就是POST请求是不会携带Cookie的。
Session的意思就是会话,我们可以通过Cookie来记录当前登录状态,当我们意外关闭网站后,下次打开该网站,仍然能够回到上次登录的地方,就好像没有离开过一样,这就是一种Session的实现方式。

5. Http长链接以及数据协商

持久连接

曾经见到过一个很有意思的面试题:当一个页面需要同时加载20张图片时,浏览器是如何处理的?看了这部分内容相信你会有答案的。我们前面讲过,从http/1.1开始支持持久连接,即一个tcp连接在完成一次http请求后不会立即被服务器关闭,后面的http请求可以复用该连接,这里涉及到一个请求头中间的关键字Connection,它只有两个值:

数据协商

顾名思义,数据协商就是客户端和服务端交互数据时会定一些规则,来确保交互的信息都满足双方的要求,该功能主要通过Content-Type实现:

请求头

响应头(与请求头对应的)

const zlib = require('zlib')
const html = fs.readFileSync('test.html')
res.writeHeader(200, {
'Content-Type': 'text/html',
'Content-Encoding': 'gzip'
)
res.end(zlib.gzipsync(html))  // 把这个html压缩后发送, 可以节省传输时间,提高性能

6. 重定向

当我们在网络上的资源更换位置后,原有的请求应该被重定向到新的地址,比如:

res.writeHead(302, { // 注意这个status code 一定要写对,302 指的是我们临时跳转到这个url,301表示永久跳转到搞路由
'Location': '/new' ,// 因为是同域跳转,这里写新的路由就可以了
})

这里需要注意的就是要合理使用状态码,如果状态码为301,那么这个时候浏览器会把新的地址缓存起来,接下来每次访问该地址都会被重定向到被缓存的地址,除非用户手动清除缓存;如果状态码为302,表示临时重定向,下次浏览器请求该资源时还是会先请求重定向之前的旧地址。

参考资料

HTTP协议原理+实践Web开发工程师必学
HTTP | MDN

上一篇下一篇

猜你喜欢

热点阅读