当前位置: 首页 > 科技观察

前端开发必懂的Nginx单页加载优化

时间:2023-03-14 01:21:56 科技观察

从前端角度简单介绍一下页面加载优化。在加载网页的时候,首先我们要看加载我们网页的过程。那些事情很费时间。比如我们访问github:Queued,Queueing:如果是HTTP/1.1,就会有队头阻塞,浏览器会阻塞每个域名。最多打开6个并发连接。停滞:浏览器必须预先分配资源并安排连接。DNSLookup:DNS解析域名。初始连接,SSL:与服务器建立连接,TCP握手,当然如果你是https,还有TLS握手。请求已发送:服务器发送数据。TTFB:等待返回数据,网络传输,即第一个字节响应时间。内容下载:接收数据。从图中可以看出,与服务器建立连接和接收数据需要花费大量的时间。当然也有DNS解析,不过这里有本地缓存??,基本没时间。gzip-减少加载量首先,我们可以通过gzip压缩我们的js和css:vue.config.js:constCompressionWebpackPlugin=require('compression-webpack-plugin')buildcfg={productionGzipExtensions:['js','css']}configureWebpack:(config)=>{config.plugins.push(newCompressionWebpackPlugin({test:newRegExp('\\.('+buildcfg.productionGzipExtensions.join('|')+')$'),threshold:8192,minRatio:0.8}))}在nginx中启用gzip:服务器模块:#使用gzip实时压缩gzipon;gzip_min_length1024;gzip_buffers416k;gzip_comp_level6;gzip_typestext/plainapplication/javascriptapplication/x-javascripttext/cssapplication/xmltext/javascript;gzip_varyon;gzip_MSIE[1-6]\.";#使用gzip_staticgzip_staticon;#使用gzip实时压缩gzipon;gzip_min_length1024;gzip_buffers416k;gzip_comp_level6;gzip_typestext/plainapplication/javascriptapplication/x-javascripttext/cssapplication/xmltext/javascript;gzip_varyon;gzip[-6]\.";#使用gzip_staticgzip_staticon;这里简单说明一下,+gzip_static是.gz文件,会自动找到对应的文件,这个和是否开启gzip以及gzip_types等无关,可以理解为priority返回.gz文件+开启gzip实时压缩请求文件,会消耗CPU。比如上面请求的文件Content-Length大于gzip_min_length,就会压缩返回。综上所述,如果打包后有.gz文件,只需要开启gzip_static即可。如果你不必启用gzip实时压缩,但我建议使用前者。另外,gzip适用于文本类型,如果用在图片上会适得其反。,所以请适当地设置gzip_types。如果想查看gzip是否开启成功,可以查看返回的headerContent-Encoding:gzip,查看文件大小。这里可以看到我们的原始文件是124kb,返回的gzip文件是44kb。压缩效率还是挺高的。:缓存控制——没有请求是浏览器-服务器缓存交互的最佳请求。有很多细节。如果您想了解更多,请阅读其他人整理的文章。我这里只说配置。:location/mobile{alias/usr/share/nginx/html/mobile/;try_filesuriuri//mobile/index.html;if(request_filename~.*\.(htm|html)){add_headerCache-Controlno-cache;}if(request_uri~*/.*\.(js|css)){#add_headerCache-Controlmax-age=2592000;expires30d;}indexindex.html;}协商缓存Last-Modified我们的单页入口文件是index.html,这个文件决定了我们要加载的js和css,所以我们为html文件设置协商缓存Cache-Controlno-cache。当我们第一次加载时,HTTP状态码为200,服务器会返回一个Last-Modified来表示文件的最后修改时间,再次刷新时,浏览器会将这个修改时间通过If发送给服务器-Modified-既然没有变化(Etag也会校验),那么服务器会返回一个304状态码,说我的文件没有变化,你直接使用缓存。EtagHTTP协议解释Etag是请求变量的实体标签。你可以理解为一个id。当文件改变时,id也会改变。这类似于Last-Modified。服务器会返回一个Etag,浏览器下次再去请求。带上If-None-Match比较返回。有些服务器的Etag计算方式不一样,做分布式的时候可能会出问题。如果文件没有改变,缓存就不会去。当然,你可以关闭它,只使用Last-Modified。强缓存当我们的单页应用打包的时候,webpack等工具会根据文件的变化生成相应的js,也就是说如果文件不变,js的hash值是不会改变的,所以我们在加载的时候可以使用强缓存js等文件,让浏览器不请求缓存时间类,直接从缓存中取值。比如上面我们设置expires(Cache-Control也行,这个优先级更高)为30天,那么浏览器访问我们同样缓存的js和css(缓存时间)时,会直接从缓存中取(缓存中的200)无需请求我们的服务器。注:该方法是基于以上打包生成hash。如果生成1.js、2.js等,那么你修改1.js中的类内容,打包出来的还是1.js。那么浏览器还是会从缓存中取出,不会再去请求了。也就是说,要使用这种方式,需要保证修改文件包后修改的hash值需要改变。强制刷新强缓存如果用的好,会有飞的感觉,但是如果用错了,就会一直跑到浏览器缓存中去。这个怎么清除,我们常用的方法是Ctrl+F5或者在浏览器控制台上。禁用缓存已选中。其实这是在请求文件的时候自动加一个headerCache-Control:no-cache。也就是说,如果我不想缓存,浏览器会老老实实地向服务器发送请求。长连接——减少握手次数。TCP握手和TLS握手还是比较耗时的。比如之前http1.1之前的连接都要经过TCP三次握手,超级耗时。好在1.1默认使用长连接,可以减少Handshake的开销,但是如果你上传一个大文件,你会发现过一定时间就会断开。这是因为Nginx默认的长连接时间是75s。可以适当延长这个时间来减少握手次数(keepalive_requests可以限制keepalive请求的最大次数)。至于上传大文件,可以选择分片上传,这里就不介绍了。server:keepalive_timeout75;keepalive_requests100;HTTP/2-更安全的HTTP,更快的HTTPS现在很多网站都启用了HTTP/2,HTTP/2最大的优点之一就是完全兼容HTTP/1、HTTP/2协议本身不需要启用SSL,但浏览器需要启用SSL才能使用HTTP/2。头部压缩、虚拟“流”传输、多路复用等技术可以充分利用带宽,减少延迟,从而大大改善上网体验。打开Nginx非常简单:server{listen443sslhttp2;ssl_certificate/etc/nginx/conf.d/ssl/xxx.com.pem;ssl_certificate_key/etc/nginx/conf.d/ssl/xxx.com.key;ssl_ciphersECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE+AES128:!MD5:!SHA1;#DeprecateunsafeencryptionSuitessl_prefer_server_cipherson;#MitigateBEASTattack}HSTS-Reduce302重定向现在大部分网站都是https,但是有个问题就是用户在输入url的时候一般不会主动输入https,还是会使用80端口,我们一般rewrite会在80端口进行重写:server{listen80;server_nametest.com;rewrite^(.*)https://host$1permanent;}但是这种重定向增加了网络开销,多一个请求,我想直接访问https怎么办下次?我们可以使用HSTS,80端口不变,服务器在443端口添加:add_headerStrict-Transport-Security"max-age=15768000;includeSubDomains;";这相当于告诉浏览器:我的网站必须严格使用HTTPS协议,在max-age时间内不允许使用HTTP,下次访问可以直接使用HTTPS,那么浏览器只会重定向到80端口第一次访问,之后访问会直接HTTPS(includeSubDomains指定此规则也适用于网站的所有子域)。SessionTicket-https会话复用我们知道在https通信过程中,SSL握手会消耗大量时间,使用非对称加密来保护会话密钥的生成。实际上传输的是通过对称加密的通信传输。那么我们每次刷新都要进行SSL握手,太费时间了。由于双方都获得了会话密钥,因此仅使用此密钥进行通信是不够的。这就是会话重用。服务器加密密钥以生成会话票证并将其发送给客户端。请求关闭后,如果客户端发起后续连接(在超时时间内),则客户端下次与服务器建立SSL连接时,会向服务器发送会话票证,服务器解锁会话票据并取出会话密钥进行加密通信。ssl_protocolsTLSv1.2TLSv1.3;#开启TLS1.2以上协议ssl_session_timeout5m;#过期时间,分钟ssl_session_ticketson;#打开浏览器的SessionTicket缓存