上一期咱們講了單頁應用的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或點贊收藏支持一下。