上一期咱们讲了单页应用的Nginx配置,本期咱们将从一个前端的角度简单介绍一下页面加载的优化工做,固然这只是浅尝辄止,毕竟我不是专业的Nginx优化人员。javascript
首先咱们要看一下咱们网页加载到底中间是个什么流程,那些东西比较耗费时间,好比咱们访问github:css
HTTP/1.1
的话,会有队头阻塞
,浏览器对每一个域名最多开 6 个并发链接。首字节响应时间
。从图中能够看出从与服务器创建链接,到接收数据,这里的时间花费是很是多的,固然还有DNS解析,不过这里有本地缓存,因此基本没有时间。html
首先咱们能够经过gzip对咱们的js
以及css
进行压缩: vue.config.js:前端
const CompressionWebpackPlugin = require('compression-webpack-plugin')
buildcfg = {
productionGzipExtensions: ['js', 'css']
}
configureWebpack: (config) => {
config.plugins.push(
new CompressionWebpackPlugin({
test: new RegExp('\\.(' + buildcfg.productionGzipExtensions.join('|') + ')$'),
threshold: 8192,
minRatio: 0.8
})
)
}
复制代码
在nginx里开启gzip:vue
server模块:java
# 使用gzip实时压缩
gzip on;
gzip_min_length 1024;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
# 使用gzip_static
gzip_static on;
复制代码
这里简单说明一下吧,webpack
gzip_static
是会自动查找对应文件的.gz
文件,这个的与gzip
开启与否以及gzip_types
等并无关联,你能够理解为优先返会.gz
文件。gzip
的开启是针对于请求文件的实时压缩,这个是会消耗cpu
的,好比说上面的请求文件的Content-Length
大于gzip_min_length
,就进行压缩返回。总结一下就是你若是打包后有.gz
文件,只须要开启gzip_static
便可,若是没有那么得启用gzip
实时压缩,不过我建议使用前者,另外gzip的适用于文本类型,图片之类的使用的话会拔苗助长,故gzip_types
请适当设置。nginx
想看gzip是否成功启用能够经过,查看返回的header头Content-Encoding: gzip
,以及查看文件的size,这里能够看到咱们原来文件的是124kb,而返回的gzip文件为44kb,压缩效率仍是蛮大的: git
浏览器于服务器的缓存交互,细提及来可就多了,想了解完整的请看其余人整理的文章吧,我只是这里从配置上略说一下:github
location /mobile {
alias /usr/share/nginx/html/mobile/;
try_files $uri $uri/ /mobile/index.html;
if ($request_filename ~ .*\.(htm|html)$){
add_header Cache-Control no-cache;
}
if ($request_uri ~* /.*\.(js|css)$) {
# add_header Cache-Control max-age=2592000;
expires 30d;
}
index index.html;
}
复制代码
咱们的单页入口文件是index.html
,这个文件呢决定了咱们要加载的js以及css,故咱们给html文件设置协商缓存Cache-Control no-cache
,当咱们首次加载时http的状态码为200,服务器会返回一个Last-Modified
表示这个文件的最后修改时间,再次刷新时浏览器会把这个修改时间经过If-Modified-Since
发送给服务器,若是没有变更(Etag也会校验),那么服务器会返回304状态码,说个人文件没有变,你直接用缓存吧。
HTTP协议解释Etag
是被请求变量的实体标记
,你能够理解为一个id,当文件变化了,这个id也会变化,这个和Last-Modified
差很少,服务器会返回一个Etag
,浏览器下次请求时会带上If-None-Match
,进行对比返回,有些服务器的Etag计算不一样,故在作分布式的时候可能会出问题,文件没改动不走缓存,固然你能够关闭这个只使用Last-Modified
。
咱们的单页应用打包时webpack等工具是会根据文件的变化生成对应的js的,也就也是文件不变的话js的hash值不变,故咱们在加载js等文件时可使用强缓存,让浏览器在缓存时间类不进行请求,直接从缓存里面取值,好比上面咱们经过设置expires(Cache-Control也行,这个优先级更高)为30天,那么浏览器下此访问咱们相同的缓存过的js和css时(缓存时间内),就直接从缓存里面拿(200 from cache),而不会请求咱们的服务器。
注意:此方法是基于上述打包生成hash而言的,假如你生成的是1.js,2.js之类的,那么你修改了1.js里面的类容,打包出来的仍是1.js,那么浏览器仍是会从缓存里面拿,不会进行请求的。也就是说使用此方式须要确保你修改了文件打包后修改的hash值须要变更。
强缓存用得好的话是飞通常的感受,可是若是在错误状况下使用就总是走浏览器缓存,如何清理这个呢,咱们经常使用的方式是Ctrl+F5
或者在浏览器控制台上把Disable cache给勾上,实际上这个是在请求文件时会自动加上一个header头Cache-Control: no-cache
,也就是说我不要缓存,那么浏览器会老老实实的向服务器发出请求。
TCP握手以及TLS握手仍是比较费时的,好比之前的http1.1以前的链接就是每一条都要进过TCP三次握手,超级费时,还好1.1默认使用了长链接,能够减小握手开销,可是假如你作大文件上传时会发现超过必定时间会断掉,这是因为Nginx
默认的长链接时间为75s,超过了就会断开,当你的网页确实要加载不少不少东西时能够适当把这个时间延长一点,以减小握手次数(keepalive_requests能够限制keep alive最大请求数),至于大文件上传吗你能够选择分片上传,这里就不作介绍了。
server:
keepalive_timeout 75;
keepalive_requests 100;
复制代码
如今不少网站都启用了HTTP/2
,HTTP/2
最大的一个优势是彻底保持了与HTTP/1
的兼容,HTTP/2 协议自己并不要求必定开启SSL
,但浏览器要求必定要启用SSL
才能使用HTTP/2
,头部压缩、虚拟的“流”传输、多路复用等技术能够充分利用带宽,下降延迟,从而大幅度提升上网体验。Nginx开启至关简单:
server {
listen 443 ssl http2;
ssl_certificate /etc/nginx/conf.d/ssl/xxx.com.pem;
ssl_certificate_key /etc/nginx/conf.d/ssl/xxx.com.key;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:!MD5:!SHA1; # 弃用不安全的加密套件
ssl_prefer_server_ciphers on; # 缓解 BEAST 攻击
}
复制代码
如今大多数网站都是https
的了,可是有个问题就是用户在输入网址时通常来讲不会主动输入https,走的仍是80端口,咱们通常会在80端口进行rewrite
重写:
server{
listen 80;
server_name test.com;
rewrite ^(.*)$ https://$host$1 permanent;
}
复制代码
但这种重定向增长了网络成本,多出了一次请求,我想下次访问时直接访问https
怎么处理?咱们可使用HSTS
,80端口的不变,在443端口的server新增:
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains;";
复制代码
这至关于告诉浏览器:我这个网站必须严格使用HTTPS
协议,在在max-age
时间内都不容许用HTTP
,下次访问你就直接用HTTPS
吧,那么浏览器只会在第一次访问时走80端口重定向,以后访问就直接是HTTPS
的了(includeSubDomains指定的话那么说明此规则也适用于该网站的全部子域名)。
咱们知道https通讯时,SSL握手会消耗大量时间,使用非对称加密保护会话密钥的生成。而真正传输的是经过对称加密进行通讯传输。那么咱们每次刷新都进行SSL握手太费时间了,既然双方都拿到会话密钥了,那么用这个密钥进行通讯不就能够了,这就是会话复用。 服务器把密钥加密后生成session ticket发送给客户端,请求关闭后,若是客户端发起后续链接(超时时间内),下次客户端再和服务器创建SSL
链接的时候,将此session ticket发送给服务器,服务器解开session ticket
后拿出会话密钥进行加密通讯。
ssl_protocols TLSv1.2 TLSv1.3; # 开启TLS1.2 以上的协议
ssl_session_timeout 5m; # 过时时间,分钟
ssl_session_tickets on; # 开启浏览器的Session Ticket缓存
复制代码
本系列更新只有利用周末和下班时间整理,比较多的内容的话更新会比较慢,但愿能对你有所帮助,请多多star或点赞收藏支持一下。