菜单
本页目录

9 HTTP 2.0

一、HTTP/2.0 的前世今生

​ 超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在TCP之上。指定了客户端发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;HTTP最早只是为了浏览器获取web服务器端资源信息的,但当时的页面的内容、排版、交互等都相对简单,所以早期的HTTP/1.0 和 1.1 都没有考虑太多效率上的问题,但随着web 2.0 甚至 web 3.0 时代的到来,HTTP 效率的问题逐渐凸显,页面上内容更加丰富(视频、图片)、排版也更加精美多样(css样式)、复杂的用户交互也越来越多(js),所以当前我们请求网站首页时所需要加载的数据总量和请求数量都越来越多,效率不足已经是亟待解决的问题了。

HTTP协议

​ 万维网 WWW(World Wide Web)发源于欧洲日内瓦量子物理实验室CERN。www 的创始人蒂姆·贝纳斯·李(TimBerners—Lee)提出了 HTTP 协议并作为 www 的支撑协议,随后成立了IETF(Internet Engineering Task Force)组织,对HTTP协议进一步完善和维护。

HTTP/2.0

​ HTTP/2.0 协议的出现主要归功于google的一个工具SPDY。

​ SPDY:由google基于TCP开发的会话层协议,用来降低网络延迟、提升带宽利用率、优化用户的网络体验等。SPDY无法取代掉HTTP协议,但可以用来增强HTTP协议。google表示,在引入SPDY协议后,页面的加载效率平均提高了60+%。

二、HTTP/2.0 升级后的新特性

1. 全新的二进制格式(Binary Format)

http/1.x诞生的时候是明文协议,其格式由三部分组成:start line(request line或者status line),header,body。

img

​ http/2.0 的格式定义更接近tcp层的方式,length定义了整个frame的开始到结束,type定义frame的类型,flags用bit位定义一些重要的参数,stream id用作流控制,剩下的payload就是request的正文了。看上去协议的格式和http/1.x完全不同了,实际上http/2.0并没有改变http/1.x的语义,只是把原来http/1.x的header和body部分用frame重新封装了一层而已。调试的时候浏览器甚至会把http/2.0的frame自动还原成http/1.x的格式。

img

2. 多路复用 (Multiplexing)

​ 在HTTP/1.1 协议中,浏览器作为客户端,在同一时间内针对同一域名下的请求有一定数量的限制,当超过数量限制时请求会被阻塞。

​ 多路复用允许同时通过单一的 HTTP/2.0 连接发起多重的请求-响应消息。因此 HTTP/2.0 可以很轻松的实现多流并行而不用依赖建立多个 TCP 连接,HTTP/2.0 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。

3. 首部压缩(Header Compression)

​ HTTP/1.1并不支持 HTTP 首部压缩,为此 SPDY 和 HTTP/2.0 应运而生, SPDY 使用的是通用的DEFLATE 算法,而 HTTP/2.0 则使用了专门为首部压缩而设计的 HPACK 算法。

img

4. 服务端数据推送(Server Push)

​ 在 HTTP/2.0 中,服务器可以对客户端的一个请求发送多个响应,如果你的请求是一个网站的首页,服务器很可能会响应主页内容、logo 以及样式文件等,因为服务器知道客户端会用到这些东西。这相当于在一个 HTML 文档内集合了所有的资源,不过与之相比,服务器推送还有一个很大的好处:可以缓存!不同页面之间可以共享缓存资源。

三、HTTP/2.0 对比 HTTP/1.1 效果展示

对比效果图:

image-20221102141314471

网址:https://http2.akamai.com/demo

四、实验:web 服务器实现 HTTP/2.0

1. 准备工作

  1. 操作系统选择CentOS 7.x,yum源自带的很多软件版本依赖就足够了
  2. httpd 版本需要在2.4.17以上,否则不支持 mod_http2
  3. Nginx 版本需要在1.10以上,否则不支持HTTP/2.0
  4. openssl版本需要在1.0.2以上,否则不支持HTTP/2.0
  5. HTTP/2.0只支持开启了https的网站,即便如此还是要比用HTTP/1.1版本未加密的效率要高

基础源:wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

扩展源:wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

2. 编译安装Apache

1、配置网络源,安装扩展源 epel-release

2、安装依赖

#安装支持HTTP/2.0的库 libnghttp2-devel
[root@localhost ~]# yum -y install gcc gcc-c++ pcre-devel openssl openssl-devel expat-devel libxml2 libxml2-devel libpng libpng-devel zlib zlib-devel libmcrypt mhash mcrypt jpeg freetype libnghttp2-devel

3、下载源码包 httpd 和其依赖,并安装(由于 rpm 的版本未达到支持 http2 )

#--no-check-certificate  忽略证书
[root@localhost ~]# wget --no-check-certificate https://dlcdn.apache.org/httpd/httpd-2.4.54.tar.gz
[root@localhost ~]# wget --no-check-certificate https://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-1.7.0.tar.gz
[root@localhost ~]# wget --no-check-certificate https://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-util-1.6.1.tar.gz
[root@localhost ~]# cp -a apr-1.7.0 httpd-2.4.46/srclib/apr
[root@localhost ~]# cp -a apr-util-1.6.1 httpd-2.4.46/srclib/apr-util
[root@localhost ~]# cd httpd-2.4.46/
[root@localhost httpd-2.4.46]# ./configure --prefix=/usr/local/apache2 --sysconfdir=/usr/local/apache2/etc --with-included-apr --enable-so --enable-deflate=shared --enable-expires=shared --enable-rewrite=shared --enable-ssl --enable-http2 && make -j 8 && make install
[root@localhost httpd-2.4.54]# echo $?
0

4、修改配置文件,开启HTTP/2.0模块和SSL模块的调用

[root@localhost httpd-2.4.54]# vim /usr/local/apache2/etc/httpd.conf 
[root@localhost httpd-2.4.54]# egrep "rewrite.so|shmcb.so|ssl.so|ssl.conf|http2.so" /usr/local/apache2/etc/httpd.conf
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule http2_module modules/mod_http2.so
LoadModule rewrite_module modules/mod_rewrite.so
Include etc/extra/httpd-ssl.conf

5、创建证书秘钥文件

[root@localhost ~]# cd /usr/local/apache2/etc/
[root@localhost etc]# openssl genrsa -out server.key 1024
[root@localhost etc]# openssl req -new -key server.key -out server.csr
[root@localhost etc]# openssl x509 -req -days 365 -sha256 -in server.csr -signkey server.key -out server.crt

6、修改配置文件,开启虚拟主机,添加443端口的虚拟主机

[root@localhost etc]# vim httpd.conf 
[root@localhost etc]# grep -A1 "^ServerName" httpd.conf
ServerName localhost:80
Protocols h2c http/1.1
[root@localhost etc]# grep -A4 "htdocs\"\$" httpd.conf
DocumentRoot "/usr/local/apache2/htdocs"
<Directory "/usr/local/apache2/htdocs">
    RewriteEngine on
    RewriteCond %{SERVER_PORT} !^443$
    RewriteRule ^(.*)?$ https://%{SERVER_NAME}$1
    
[root@localhost etc]# 
[root@localhost etc]# vim extra/httpd-ssl.conf
<VirtualHost _default_:443>
DocumentRoot "/usr/local/apache2/htdocs"
Protocols h2 http/1.1					#httpd-ssl.conf中相当于仅修改了此处
#因为创建的证书和秘钥文件符合配置文件中默认的目录和文件名,所以没有写但单独的调用
[root@localhost etc]# 

7、检查配置文件并重启httpd服务,浏览器单独验证httpd是否支持HTTP/2.0协议

[root@localhost etc]# ln -s /usr/local/apache2/bin/* /usr/local/bin/
[root@localhost etc]# apachectl -t
Syntax OK
[root@localhost etc]# apachectl star

效果展示:

Chrome 浏览器查看:开发者模式 —> Network —> 右键标题勾选 Protocol —> 查看 Protocol 为 h2

Chrome 浏览器查看:开发者模式 —> Console —> 输入 window.chrome.loadTimes() —> 结果中查看 connectionInfo: "h2"

image-20221101223613273

image-20210318025039636

Firefox 浏览器查看:开发者模式 —> Network —> 网页头信息 Headers —> Version: HTTP/2.0

Safari 浏览器查看:开发者模式 —> Resources —> 网页头信息 —> Resource —> Protocol HTTP/2

检测网址:https://myssl.com/

3. 编译安装Nginx(可以换另外一台机器)

  1. 下载Nginx源码软件包

    	[root@localhost lnamp]# wget http://nginx.org/download/nginx-1.19.8.tar.gz
    
    
  2. 编译安装nginx软件包

    	[root@localhost lnamp]# tar -xf nginx-1.19.8.tar.gz 
    	[root@localhost lnamp]# cd nginx-1.19.8/
    	[root@localhost nginx-1.19.8]# useradd -r -s /sbin/nologin nginx
    	[root@localhost nginx-1.19.8]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module
    	[root@localhost nginx-1.19.8]# make
    	[root@localhost nginx-1.19.8]# make install
    
  3. 修改配置文件,开启SSL和HTTP/2.0

    	[root@localhost ~]# cd /usr/local/nginx/conf
    	[root@localhost conf]# vim nginx.conf
    	user nginx nginx;
    	worker_processes  auto;
    	http {
    	    server {
    	        listen       80;
    	        server_name  www.linuxlc.com;
    	        ... ...
    	        location / {
    	            root   html;
    	            index  index.html index.htm;
    	            rewrite ^(.*)$ https://www.linuxlc.com/$1;
    	        }
    	    }
    	    server {
    	        listen       443 ssl http2;
    	        server_name  www.linuxlc.com;
    
    	        ssl_certificate     /usr/local/apache2/etc/server.crt;
    	        ssl_certificate_key  /usr/local/apache2/etc/server.key;
    
    	        ssl_session_cache    shared:SSL:1m;
    	        ssl_session_timeout  5m;
    
    	        ssl_ciphers  HIGH:!aNULL:!MD5;
    	        ssl_prefer_server_ciphers  on;
    
    	        location / {
    	            root   html;
    	            index  index.html index.htm;
    	        }
    	    }
    	}
    
  4. 重启Nginx服务,验证HTTP/2.0效果

    	[root@localhost conf]# /usr/local/apache2/bin/apachectl stop
    	[root@localhost conf]# /usr/local/nginx/sbin/nginx
    

    image-20210318031808969