http协议总结

为何要进行URI编码

1.在传递数据的过程当中,若是存在用在分隔符的保留字怎么办?
2.对可能产生歧义性的数据进行编码
  1.再也不ascii码范围内的字符
  2.ascii码中不可显示的字符
  3.uri中规定的保留字符
  4.不安全字符,空格,引号,尖括号
  
示例:
https://www.baidu.com/s?wd=?#! 若是不进行编码#后面的后所有截断

https://www.baidu.com/s?wd=中文

https://www.baidu.com/s?wd='>中文

http协议

Http协议,全称是HyperText Tansfer Protocol,中文叫超文本传输协议,是互联网最多见的协议。Http最重要的是www(World Wide Web)服务,也叫web服务器,中文叫“万维网”。
web服务端口默认是80,另一个加密的www服务应用https默认端口是443,主要用于支付,网银相关业务

http协议版本

http协议诞生以来有若干个版本,主要是http/1.0 http/1.1

http/1.0规定浏览器和服务器只能保持短暂的链接,浏览器的每次请求都须要和服务器创建一个TCP链接,服务器完成请求后即断开TCP链接,服务器不跟踪每一个连接,也不记录请求

http/1.1是对HTTP的缺陷进行重点修复,从可扩展性,缓存,带宽优化,持久链接,host头,错误通知等访问改进。
http/1.1支持长链接,增长了更多的请求头和响应头信息,例如配置请求头的Connection的值为keep-alive,表示请求结果返回后保持链接

http请求方法

1    GET    请求指定的页面信息,并返回实体主体。
2    HEAD    相似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3    POST    向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会致使新的资源的创建和/或已有资源的修改。
4    PUT    从客户端向服务器传送的数据取代指定的文档的内容。
5    DELETE    请求服务器删除指定的页面。
6    CONNECT    HTTP/1.1协议中预留给可以将链接改成管道方式的代理服务器。
7    OPTIONS    容许客户端查看服务器的性能。
8    TRACE    回显服务器收到的请求,主要用于测试或诊断。

http状态码

HTTp状态码表示web服务器响应http请求状态的数字代码
常见状态码以及做用是
1**    信息,服务器收到请求,须要请求者继续执行操做
2**    成功,操做被成功接收并处理
3**    重定向,须要进一步的操做以完成请求
4**    客户端错误,请求包含语法错误或没法完成请求
5**    服务器错误,服务器在处理请求的过程当中发生了错误

http报文

http请求报文

HTTP请求由请求行,请求头部,空行,请求报文主体几个部分组成

请求报文的格式:
起始行: <method> <request-URL> <version>
头部:   <headers>
主体:   <entity-body>
GET /books/?sex=man&name=Professional HTTP/1.1
 Host: www.example.com  主机名
 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)Gecko/20050225 Firefox/1.0.1  客户端类型
 Accept-Encoding:gzip,deflate    支持压缩
 Accept-Language:zh-cn  支持语言类型
 Connection: Keep-Alive  长连接
 
sex=man&name=Professional
 
请求行:

 请求报文第一行,表示客户端想要什么
由请求方法 url    协议版本   组成

请求头:

 请求头由    
关键字    :    值    组成
经过客户端把请求相关信息告诉服务器


空行

请求头信息以后是一个空行,发送回车和换行符,通知web服务器如下没有请求头信息了


请求体:

请求体中包含了要发送给web服务器的数据信息,请问报文主体不用于get方法,而是用于post方法。
post方法适用于客户端填写表单的场合。

http响应报文

状态行
响应头(Response Header)
响应正文
HTTP/1.1 200 OK
Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:23:42 GMT
Content-Length:112
<html>...

状态行:

状态行,用来讲明服务器响应客户端的情况,通常分为协议版本号,数字状态码,状态状况

响应头部:

常见响应头信息
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html;charset=utf-8
Date: Mon, 13 Aug 2018 06:06:54 GMT
Expires: Mon, 13 Aug 2018 06:06:54 GMT

空白行:
通知客户端空行如下没有头部信息了
响应报文主体
主要包含了返回给客户端的数据,能够是文本,二进制(图片,视频)

https

http存在的问题

窃听 - 对称加密
传递密钥 - 非对称加密
安全速度 - 非对称加密+对称加密
中间人攻击 - 证书
证书伪造 - 消息摘要
摘要伪造 - 数字签名

如何解决

在OSI七层模型中,应用层是HTTP协议,在应用层之下就是表示层,也就是TLS协议发挥做用的一层。
TLS协议经过(握手、交换秘钥、告警、加密)等方式作到数据的安全加密。html

openssl

Netscape网景公司建立的第一代浏览器,且为了提升浏览器访问网站的安全性,在TCP/IP层的传输层与应用层之间建立了一个SSL(Secure Sockets Layer),安全套接字层。

SSL是一个库,为了让应用层讲数据传递给传输层以前,调用ssl层的功能,对数据进行加密。

可是SSL(v2 v3)是网景公司定义的,协议不够开放,所以TSL(传输层安全协议)出现了,流行的版本是(TSL v1== SSL v3

ssl密钥协商过程

https完整创建链接的过程

证书的申请颁发过程

证书的有效性链式证实

websocket

目的

即时通信,替代轮询

网站上的即时通信是很常见的,好比网页的QQ,聊天系统等。按照以往的技术能力一般是采用轮询、Comet技术解决。

HTTP协议是非持久化的,单向的网络协议,在创建链接后只容许浏览器向服务器发出请求后,服务器才能返回相应的数据。当须要即时通信时,经过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,而后将最新的数据返回给浏览器。这样的方法最明显的缺点就是须要不断的发送请求,并且一般HTTP request的Header是很是长的,为了传输一个很小的数据 须要付出巨大的代价,是很不合算的,占用了不少的宽带。

缺点:会致使过多没必要要的请求,浪费流量和服务器资源,每一次请求、应答,都浪费了必定流量在相同的头部信息上

然而WebSocket的出现能够弥补这一缺点。在WebSocket中,只须要服务器和浏览器经过HTTP协议进行一个握手的动做,而后单独创建一条TCP的通讯通道进行数据的传送。

原理

WebSocket同HTTP同样也是应用层的协议,可是它是一种双向通讯协议,是创建在TCP之上的。

链接过程(握手过程)

1. 浏览器、服务器创建TCP链接,三次握手。这是通讯的基础,传输控制层,若失败后续都不执行。
2. TCP链接成功后,浏览器经过HTTP协议向服务器传送WebSocket支持的版本号等信息。(开始前的HTTP握手)
3. 服务器收到客户端的握手请求后,一样采用HTTP协议回馈数据。
4. 当收到了链接成功的消息后,经过TCP通道进行传输通讯。

websocket与http的关系

相同点
1. 都是同样基于TCP的,都是可靠性传输协议。
2. 都是应用层协议。
不一样点
1. WebSocket是双向通讯协议,模拟Socket协议,能够双向发送或接受信息。HTTP是单向的。
2. WebSocket是须要握手进行创建链接的。

websocket与http的关系

WebSocket在创建握手时,数据是经过HTTP传输的。可是创建以后,在真正传输时候是不须要HTTP协议的。

WebSocket与Socket的关系

Socket其实并非一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。

当两台主机通讯时,必须经过Socket链接,Socket则利用TCP/IP协议创建TCP链接。TCP链接则更依靠于底层的IP协议,IP协议的链接则依赖于链路层等更低层次。

WebSocket则是一个典型的应用层协议。

区别
Socket是传输控制层协议,WebSocket是应用层协议。

websocket机制

传统 HTTP 请求响应客户端服务器交互图

websocket 请求响应客户端服务器交互图

相对于传统 HTTP 每次请求-应答都须要客户端与服务端创建链接的模式,WebSocket 是相似 Socket 的 TCP 长链接的通信模式,一旦 WebSocket 链接创建后,后续数据都以帧序列的形式传输。在客户端断开 WebSocket 链接或 Server 端断掉链接前,不须要客户端和服务端从新发起链接请求。在海量并发及客户端与服务器交互负载流量大的状况下,极大的节省了网络带宽资源的消耗,有明显的性能优点,且客户端发送和接受消息是在同一个持久链接上发起,实时性优点明显。

websocket握手过程

客户端链接报文
GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: 
http://localhost
:8080
Sec-WebSocket-Version: 13

Connection: Upgrade:表示要升级协议
Upgrade: websocket:表示要升级到websocket协议
Sec-WebSocket-Version: 13:表示websocket的版本
Sec-WebSocket-Key:与后面服务端响应首部的Sec-WebSocket-Accept是配套的,提供基本的防御,好比恶意的链接,或者无心的链接。
WebSocket 服务端响应报文
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
Sec-WebSocket-Key/Accept的做用
避免服务端收到非法的websocket链接
确保服务端理解websocket链接
用浏览器里发起ajax请求,设置header时,Sec-WebSocket-Key以及其余相关的header是被禁止的
Sec-WebSocket-Key主要目的并非确保数据的安全性,由于Sec-WebSocket-Key、Sec-WebSocket-Accept的转换计算公式是公开的,并且很是简单,最主要的做用是预防一些常见的意外状况(非故意的)
Sec-WebSocket-Accept的计算
Sec-WebSocket-Accept根据客户端请求首部的Sec-WebSocket-Key计算出来。 计算公式为:

将Sec-WebSocket-Key跟258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接。
经过SHA1计算出摘要,并转成base64字符串


1.value = headers['Sec-WebSocket-Key'] + magic_string 
拿到客户端发送的key,拼接magicstring

2.ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
进行sha1,base64加密

3."Sec-WebSocket-Accept: ac
将加密结果返回
import socket, base64, hashlib

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('127.0.0.1', 9527))
sock.listen(5)
# 获取客户端socket对象
conn, address = sock.accept()
# 获取客户端的【握手】信息
data = conn.recv(1024)
print(data)
"""
b'GET /ws HTTP/1.1\r\n
Host: 127.0.0.1:9527\r\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\r\n
Accept-Encoding: gzip, deflate\r\n
Sec-WebSocket-Version: 13\r\n
Origin: http://localhost:63342\r\n
Sec-WebSocket-Extensions: permessage-deflate\r\n
Sec-WebSocket-Key: jocLOLLq1BQWp0aZgEWL5A==\r\n
Cookie: session=6f2bab18-2dc4-426a-8f06-de22909b967b\r\n
Connection: keep-alive, Upgrade\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
Upgrade: websocket\r\n\r\n'
"""

# magic string为:258EAFA5-E914-47DA-95CA-C5AB0DC85B11
magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'


def get_headers(data):
    header_dict = {}
    header_str = data.decode("utf8")
    for i in header_str.split("\r\n"):
        if str(i).startswith("Sec-WebSocket-Key"):
            header_dict["Sec-WebSocket-Key"] = i.split(":")[1].strip()

    return header_dict


def get_header(data):
    """
     将请求头格式化成字典
     :param data:
     :return:
     """
    header_dict = {}
    data = str(data, encoding='utf-8')

    header, body = data.split('\r\n\r\n', 1)
    header_list = header.split('\r\n')
    for i in range(0, len(header_list)):
        if i == 0:
            if len(header_list[i].split(' ')) == 3:
                header_dict['method'], header_dict['url'], header_dict['protocol'] = header_list[i].split(' ')
        else:
            k, v = header_list[i].split(':', 1)
            header_dict[k] = v.strip()
    return header_dict


headers = get_headers(data)  # 提取请求头信息
# 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
               "Upgrade:websocket\r\n" \
               "Connection: Upgrade\r\n" \
               "Sec-WebSocket-Accept: %s\r\n" \
               "WebSocket-Location: ws://127.0.0.1:9527\r\n\r\n"

value = headers['Sec-WebSocket-Key'] + magic_string
print(value)
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest())
response_str = response_tpl % (ac.decode('utf-8'))
# 响应【握手】信息
conn.send(response_str.encode("utf8"))

while True:
    msg = conn.recv(8096)
    print(msg)

websocket加密

import struct
msg_bytes = "hello".encode("utf8")
token = b"\x81"
length = len(msg_bytes)

if length < 126:
    token += struct.pack("B", length)
elif length <= 0xFFFF:
    token += struct.pack("!BH", 126, length)
else:
    token += struct.pack("!BQ", 127, length)

msg = token + msg_bytes

print(msg)
websocket数据帧格式
WebSocket客户端、服务端通讯的最小单位是帧,由1个或多个帧组成一条完整的消息(message)。

发送端:将消息切割成多个帧,并发送给服务端
接收端:接收消息帧,并将关联的帧从新组装成完整的消息


  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-------+-+-------------+-------------------------------+
 |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
 |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
 |N|V|V|V|       |S|             |   (if payload len==126/127)   |
 | |1|2|3|       |K|             |                               |
 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
 |     Extended payload length continued, if payload len == 127  |
 + - - - - - - - - - - - - - - - +-------------------------------+
 |                               |Masking-key, if MASK set to 1  |
 +-------------------------------+-------------------------------+
 | Masking-key (continued)       |          Payload Data         |
 +-------------------------------- - - - - - - - - - - - - - - - +
 :                     Payload Data continued ...                :
 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
 |                     Payload Data continued ...                |
 +---------------------------------------------------------------+

http安全问题

xss攻击

1.黑客往网页里注入恶意脚本代码
2.当用户访问时获取到包含恶意代码的网页
3.经过恶意脚本,黑客能够获取和控制用户信息
反射型(非持久型)XSS
诱导用户点击恶意连接来形成一次性攻击

1.黑客把带有恶意脚本代码参数的URL地址发送给用户
2.用户点击此连接
3.服务器端获取请求参数而且直接使用,服务器反射回结果页面
4.反射型XSS攻击是一次性的,必需要经过用户点击连接才能发起
5.一些浏览器如Chrome其内置了一些XSS过滤器,能够防止大部分反射型XSS攻击
6.反射型XSS其实就是服务器没有对恶意的用户输入进行安全处理就直接反射响应内容,致使恶意代码在浏览器中执行的一种XSS漏洞
const express = require('express');


存储型(持久型)XSS

黑客将代码存储到漏洞服务器中,用户浏览相关页面发起攻击

1.黑客将恶意脚本代码上传或存储到漏洞服务器
2.服务器把恶意脚本保存到服务器
3.当正常客户访问服务器时,服务器会读取恶意数据而且直接使用
4.服务器会返回含有恶意脚本的页面


DOM-Based型XSS
不须要服务器端支持,是因为DOM结构修改致使的,基于浏览器DOM解析的攻击

1.用户打开带有恶意的连接
2.浏览器在DOM解析的时候直接使用恶意数据
3.用户中招
4.常见的触发场景就是在修改innerHTML outerHTML document.write的时候
xss攻击对比
类型 反射型 存储型
持久性 非持久 持久化(存储在服务器)
触发时机 须要用户点击 不须要用户交互也能够触发
危害 危害较小 危害更大
xss防护
1.对字符进行编码
function htmlEncode(str) {
  return String(str)
    .replace(/&/g, '&amp;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

2.对js进行编码转译
   //使用“\”对特殊字符进行转义,除数字字母以外,小于127使用16进制“\xHH”的方式进行编码,大于用unicode(很是严格模式)。
        var JavaScriptEncode = function (str) {
            var hex = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
            function changeTo16Hex(charCode) {
                return "\\x" + charCode.charCodeAt(0).toString(16);
            }

            function encodeCharx(original) {
                var found = true;
                var thecharchar = original.charAt(0);
                var thechar = original.charCodeAt(0);
                switch (thecharchar) {
                    case '\n': return "\\n"; break; //newline
                    case '\r': return "\\r"; break; //Carriage return
                    case '\'': return "\\'"; break;
                    case '"': return "\\\""; break;
                    case '\&': return "\\&"; break;
                    case '\\': return "\\\\"; break;
                    case '\t': return "\\t"; break;
                    case '\b': return "\\b"; break;
                    case '\f': return "\\f"; break;
                    case '/': return "\\x2F"; break;
                    case '<': return "\\x3C"; break;
                    case '>': return "\\x3E"; break;
                    default:
                        found = false;
                        break;
                }
                if (!found) {
                    if (thechar > 47 && thechar < 58) { //数字
                        return original;
                    }

                    if (thechar > 64 && thechar < 91) { //大写字母
                        return original;
                    }

                    if (thechar > 96 && thechar < 123) { //小写字母
                        return original;
                    }

                    if (thechar > 127) { //大于127用unicode
                        var c = thechar;
                        var a4 = c % 16;
                        c = Math.floor(c / 16);
                        var a3 = c % 16;
                        c = Math.floor(c / 16);
                        var a2 = c % 16;
                        c = Math.floor(c / 16);
                        var a1 = c % 16;
                        return "\\u" + hex[a1] + hex[a2] + hex[a3] + hex[a4] + "";
                    }
                    else {
                        return changeTo16Hex(original);
                    }

                }
            }

csrf

Cross Site Request Forgery 跨站请求伪造

1.用户A登陆银行网站,登陆成功后会设置cookie
2.黑客诱导用户A登陆到黑客的站点,而后会返回一个页面
3.用户访问这个页面时,这个页面会伪造一个转帐请求到银行网站
防护
1.用户不知情 验证码 影响用户体验
2.跨站请求 使用refer验证 不可靠
3.参数伪造 token 最主流的防护CSRF

DDOS攻击

分布式拒绝服务(Distribute Denial Of Service)

黑客控制大量的肉鸡向受害主机发送非正常请求,致使目标主机耗尽资源不能为合法用户提供服务
验证码是咱们在互联网十分常见的技术之一。不得不说验证码是可以有效地防止屡次重复请求的行为。
限制请求频率是咱们最多见的针对 DDOS 攻击的防护措施。其原理为设置每一个客户端的请求频率的限制
增长机器增长服务带宽。只要超过了攻击流量即可以免服务瘫痪
设置本身的业务为分布式服务,防止单点失效
使用主流云系统和 CDN(云和 CDN 其自身有 DDOS 的防范做用)
优化资源使用提升 web server 的负载能力

HTTP劫持

在用户的客户端与其要访问的服务器通过网络协议协调后,两者之间创建了一条专用的数据通道,用户端程序在系统中开放指定网络端口用于接收数据报文,服务器端将所有数据按指定网络协议规则进行分解打包,造成连续数据报文。
用户端接收到所有报文后,按照协议标准来解包组合得到完整的网络数据。其中传输过程当中的每个数据包都有特定的标签,表示其来源、携带的数据属性以及要到何处,全部的数据包通过网络路径中ISP的路由器传输接力后,最终到达目的地,也就是客户端。
HTTP劫持是在使用者与其目的网络服务所创建的专用数据通道中,监视特定数据信息,提示当知足设定的条件时,就会在正常的数据流中插入精心设计的网络数据报文,目的是让用户端程序解释“错误”的数据,并以弹出新窗口的形式在使用者界面展现宣传性广告或者直接显示某网站的内容。

http缓存机制

Web 缓存大体能够分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。

浏览器缓存也包含不少内容: HTTP 缓存、indexDB、cookie、localstorage 等等。这里咱们只讨论 HTTP 缓存相关内容。

在具体了解 HTTP 缓存以前先来明确几个术语:

缓存命中率:从缓存中获得数据的请求数与全部请求数的比率。理想状态是越高越好。
过时内容:超过设置的有效时间,被标记为“陈旧”的内容。一般过时内容不能用于回复客户端的请求,必须从新向源服务器请求新的内容或者验证缓存的内容是否仍然准备。
验证:验证缓存中的过时内容是否仍然有效,验证经过的话刷新过时时间。
失效:失效就是把内容从缓存中移除。当内容发生改变时就必须移除失效的内容。
浏览器缓存主要是 HTTP 协议定义的缓存机制。HTML meta 标签,例如

<META HTTP-EQUIV="Pragma" CONTENT="no-store">

含义是让浏览器不缓存当前页面。可是代理服务器不解析 HTML 内容,通常应用普遍的是用 HTTP 头信息控制缓存。

浏览器缓存分类

浏览器缓存分为强缓存和协商缓存,浏览器加载一个页面的简单流程以下:

1.浏览器先根据这个资源的http头信息来判断是否命中强缓存。若是命中则直接加在缓存中的资源,并不会将请求发送到服务器。

2.若是未命中强缓存,则浏览器会将资源加载请求发送到服务器。服务器来判断浏览器本地缓存是否失效。若可使用,则服务器并不会返回资源信息,浏览器继续从缓存加载资源。

3.若是未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器加载新资源,并更新缓存。

强缓存

命中强缓存时,浏览器并不会将请求发送给服务器。在Chrome的开发者工具中看到http的返回码是200,可是在Size列会显示为(from cache)。

强缓存是利用http的返回头中的Expires或者Cache-Control两个字段来控制的,用来表示资源的缓存时间。

Expires

缓存过时时间,用来指定资源到期的时间,是服务器端的具体的时间点。也就是说,Expires=max-age + 请求时间,须要和Last-modified结合使用。但在上面咱们提到过,cache-control的优先级更高。 Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过时时间前浏览器能够直接从浏览器缓存取数据,而无需再次请求。

该字段会返回一个时间,好比Expires:Thu,31 Dec 2037 23:59:59 GMT。这个时间表明着这个资源的失效时间,也就是说在2037年12月31日23点59分59秒以前都是有效的,即命中缓存。这种方式有一个明显的缺点,因为失效时间是一个绝对时间,因此当客户端本地时间被修改之后,服务器与客户端时间误差变大之后,就会致使缓存混乱。因而发展出了Cache-Control。


Cache-Control

Cache-Control是一个相对时间,例如Cache-Control:3600,表明着资源的有效期是3600秒。因为是相对时间,而且都是与客户端时间比较,因此服务器与客户端时间误差也不会致使问题。
Cache-Control与Expires能够在服务端配置同时启用或者启用任意一个,同时启用的时候Cache-Control优先级高。

Cache-Control 能够由多个字段组合而成,主要有如下几个取值:

1. max-age 指定一个时间长度,在这个时间段内缓存是有效的,单位是s。例如设置 Cache-Control:max-age=31536000,也就是说缓存有效期为(31536000 / 24 / 60 * 60)天,第一次访问这个资源的时候,服务器端也返回了 Expires 字段,而且过时时间是一年后。

在没有禁用缓存而且没有超过有效时间的状况下,再次访问这个资源就命中了缓存,不会向服务器请求资源而是直接从浏览器缓存中取。

2. s-maxage 同 max-age,覆盖 max-age、Expires,但仅适用于共享缓存,在私有缓存中被忽略。

3. public 代表响应能够被任何对象(发送请求的客户端、代理服务器等等)缓存。

4. private 代表响应只能被单个用户(多是操做系统用户、浏览器用户)缓存,是非共享的,不能被代理服务器缓存。

5. no-cache 强制全部缓存了该响应的用户,在使用已缓存的数据前,发送带验证器的请求到服务器。不是字面意思上的不缓存。

6. no-store 禁止缓存,每次请求都要向服务器从新获取数据。

七、must-revalidate指定若是页面是过时的,则去服务器进行获取。这个指令并不经常使用,就不作过多的讨论了。

协商缓存

若未命中强缓存,则浏览器会将请求发送至服务器。服务器根据http头信息中的Last-Modify/If-Modify-Since或Etag/If-None-Match来判断是否命中协商缓存。若是命中,则http返回码为304,浏览器从缓存中加载资源。

Last-Modify/If-Modify-Since

浏览器第一次请求一个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是一个时间标识该资源的最后修改时间,例如Last-Modify: Thu,31 Dec 2037 23:59:59 GMT。

当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存以前返回的Last-Modify。服务器收到If-Modify-Since后,根据资源的最后修改时间判断是否命中缓存。

若是命中缓存,则返回http304,而且不会返回资源内容,而且不会返回Last-Modify。因为对比的服务端时间,因此客户端与服务端时间差距不会致使问题。可是有时候经过最后修改时间来判断资源是否修改仍是不太准确(资源变化了最后修改时间也能够一致)。因而出现了ETag/If-None-Match。


ETag/If-None-Match

与Last-Modify/If-Modify-Since不一样的是,Etag/If-None-Match返回的是一个校验码(ETag: entity tag)。ETag能够保证每个资源是惟一的,资源变化都会致使ETag变化*。ETag值的变动则说明资源状态已经被修改。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。

ETag扩展说明

咱们对ETag寄予厚望,但愿它对于每个url生成惟一的值,资源变化时ETag也发生变化。神秘的Etag是如何生成的呢?以Apache为例,ETag生成靠如下几种因子

文件的i-node编号,此i-node非彼iNode。是Linux/Unix用来识别文件的编号。是的,识别文件用的不是文件名。使用命令’ls –I’能够看到。
文件最后修改时间
文件大小
生成Etag的时候,可使用其中一种或几种因子,使用抗碰撞散列函数来生成。因此,理论上ETag也是会重复的,只是几率小到能够忽略。
既生Last-Modified何生Etag?
你可能会以为使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为何还须要Etag(实体标识)呢?HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

1. Last-Modified标注的最后修改只能精确到秒级,若是某些文件在1秒钟之内,被修改屡次的话,它将不能准确标注文件的修改时间

2. 若是某些文件会被按期生成,当有时内容并无任何变化,但Last-Modified却改变了,致使文件无法使用缓存

3.有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的惟一标识符,可以更加准确的控制缓存。Last-Modified与ETag是能够一块儿使用的,服务器会优先验证ETag,一致的状况下,才会继续比对Last-Modified,最后才决定是否返回304。

浏览器缓存与用户行为有关

用户操做 Expires/Cache-Control Last-Modified/Etag
地址栏回车 有效 有效
页面连接跳转 有效 有效
新开窗口 有效 有效
前进、后退 有效 有效
F5刷新 无效 有效
Ctrl+F5刷新 无效 无效

浏览器第一次请求

浏览器再次请求

http持久链接和管线化节省通讯量

持久链接(keep-alive)模式

HTTP1.1规定了默认保持长链接(HTTP persistent connection ,也有翻译为持久链接);数据传输完成了保持TCP链接不断开(不发RST包、不四次握手),等待在同域名下继续用这个通道传输数据;相反的就是短链接。

HTTP 1.1版本支持持久链接 1.0版本不支持

与非持久链接的区别:

持久链接使客户端到服务器端链接持续有效,避免了从新创建链接

大大减小了链接的创建以及关闭时延。HTTP链接是创建在TCP协议之上的,创建一条TCP链接须要三次握手,TCP链接关闭时须要四次挥手。这些都是须要时间的

管线化

管线化机制须经过永久链接(persistent connection)完成,仅HTTP/1.1支持此技术(HTTP/1.0不支持)

在使用持久链接的状况下,某个链接消息的传递相似于

请求1 -> 响应1 -> 请求2 -> 响应2

管线化:某个链接上的消息变成了相似这样 

请求1 -> 请求2 -> 请求3 -> 响应1 -> 响应2 -> 响应3

持久链接与管线化的区别

 1. 那么持久链接和管线化的区别在于:

  持久链接的一个缺点是请求和响应式是顺序执行的,只有在请求1的响应收到以后,才会发送请求2,而管线化不须要等待上一次请求获得响应就能够进行下一次请求。实现并行发送请求。 

  2. 只有GET和HEAD要求能够进行管线化,而POST则有所限制

  3. 初次建立链接时也不该启动管线机制,由于对方(服务器)不必定支持HTTP/1.1版本的协议。

       4.HTTP1.1要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要求对于管线化的请求不失败,并且如今不少服务器端和代理程序对管线化的支持并很差,现代浏览器Chrome和Firefox默认并未开启管线化支持。
相关文章
相关标签/搜索