本文篇幅較長,所有閱讀完大約須要10分鐘。如下是本文概覽。css
原文連接:HTTP headers for the responsible developer
現在,使用網絡是許多人的默認狀態。 咱們都花時間購物,聊天,閱讀文章,尋找方向等信息。 網絡將咱們與整個世界聯繫起來,但大多數狀況下,網絡將人們鏈接起來。 我本身已經使用網絡已有20年了,八年前,當我成爲網絡開發人員時,我與它的關係發生了變化。html
開發人員鏈接了人們。
開發人員幫助了人們。
開發人員支持着人們。
**
開發人員有能力爲每一個人構建Web服務,但須要負責任地使用該功能。 最重要的是,創建有助於和幫助人們的事物。
在本文中,我想分享HTTP Header 如何幫助您構建更好的產品,以便爲每一個人提供更好的Web服務。前端
咱們先談談HTTP。 HTTP是計算機用於經過Web請求和發送數據的協議。
當瀏覽器從服務器請求資源時,它使用HTTP。 此請求包括一組鍵值對,提供瀏覽器版本或其理解的文件格式等信息。 這些鍵值對稱爲 request headers。
服務器使用所請求的資源進行應答,但也會發送 response headers,提供有關資源或服務器自己的信息。git
Request:
GET https://the-responsible.dev/
Accept: text/html,application/xhtml+xml,application/xml
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,de;q=0.7
...
Response:
Connection: keep-alive
Content-Type: text/html; charset=utf-8
Date: Mon, 11 Mar 2019 12:59:38 GMT
...
Response Body
複製代碼
HTTP是當今網絡的基礎,它提供了許多改善用戶體驗的方法。 讓咱們深刻探討如何使用HTTP Header構建安全,經濟且值得尊重的Web服務。github
我歷來沒有在瀏覽互聯網時感到不安全。 我對網絡的瞭解越多,我就越關注。 您能夠閱讀有關黑客可能會改變全球CDN託管的 庫,隨機網站在其訪問者的瀏覽器中挖掘加密貨幣以及人們將社交工程按期用於成功的開源項目。 這很差,但爲何要關心呢?web
若是您今天正在爲網絡構建,那麼您不只要編寫代碼。 現在,Web開發包括許多在同一站點上工做的人。 您可能也提供了大量的開源代碼。 此外,您能夠包含多個第三方腳本用於銷售目的。 數百人提供您網站上運行的代碼。 開發人員必須應對這一現實。算法
你應該相信全部這些人及其全部源代碼嗎?
我認爲你不能相信任何第三方代碼。 幸運的是,有一些方法能夠保護您的網站並使其更安全。 此外,像頭盔這樣的工具能夠幫助確保你的快遞申請的安全 。
若是您想分析您的網站上運行了多少第三方代碼,您能夠查看您選擇的開發人員工具的網絡面板,或者嘗試使用Request Map Generator。chrome
安全鏈接是安全互聯網的基礎。 若是沒有經過HTTPS運行的加密請求,您沒法肯定您的網站與訪問者之間是否存在任何人。 一我的能夠快速啓動一個公共wifi網絡,並對一個鏈接任何人進行中間攻擊。 你多久使用一次公共wifi? 並且,你常常檢查它是否值得信賴?express
幸運的是,今天TLS證書是免費的; HTTPS已成爲一種標準,瀏覽器供應商僅在安全鏈接上提供最早進的功能,甚至將非HTTPS網站標記爲不安全,從而推進HTTPS的採用。 不幸的是,咱們一直沒有安全瀏覽。 當有人想打開一個網站時,他們沒有將協議輸入地址欄(他們爲何要這樣作?)。 此操做會致使未加密的HTTP請求。 安全運行站點而後重定向到HTTPS。 可是若是有人攔截了第一個無擔保的請求怎麼辦?
您可使用HSTS response headers(HTTP嚴格傳輸安全性)告訴瀏覽器您的網站僅經過HTTPS工做。npm
Strict-Transport-Security: max-age=1000; includeSubDomains; preload
複製代碼
此 Header 告訴瀏覽器您不想使用HTTP請求,它會自動使用安全鏈接向相同的源發出如下請求。 當您嘗試再次經過HTTP訪問相同的URL時,瀏覽器將在內部使用HTTPS和重定向。
您能夠配置此設置應該激活的時間長度(以秒爲單位的 max-age),以便您可能但願再次使用HTTP。 若是要包含子域,則可使用 includeSubDomains 配置子域。
若是您想加倍努力並但願確保瀏覽器永遠不會經過HTTP請求您的站點,您還能夠設置preload指令並將您的站點提交到全局列表。 若是您的站點的HSTS配置知足最小年齡爲一年的要求而且對於子域是活動的,則它能夠包含在僅經過HTTPS工做的站點的內部瀏覽器記錄中。
你有沒有想過爲何你不能再經過HTTP使用my-site.dev這樣的本地環境了? 此內部記錄的緣由是 - .dev域名自動包含在此列表中,由於它在2019年2月成爲真正的頂級域名。
HSTS Header 不只使您的網站更安全,並且還加快了它的速度。 想象一下有人經過慢速移動鏈接訪問您的網站。 若是第一個請求是經過HTTP進行的,只是爲了接收重定向,那麼用戶能夠花費幾秒鐘而不會看到任何內容。 使用HSTS,您能夠節省這些時間,瀏覽器會自動使用HTTPS。
既然您的站點經過安全鏈接運行,您可能會遇到這樣的問題:因爲混合內容策略,瀏覽器開始阻止發送到不安全地址的請求。 內容安全策略(CSP)標頭提供了處理這些狀況的絕佳方法。 您能夠經過提供的HTML中的元素或HTTP Header 定義CSP規則集。Content-Security-Policy: upgrade-insecure-requests
upgrade-insecure-requests 指令告訴瀏覽器神奇地將全部HTTP請求升級到HTTPS。
CSP不只僅是關於使用的協議。 它提供了詳細的方法來定義站點上容許的資源和操做。 您能夠定義例如應該執行哪些腳本或應該從哪裏加載圖像。 若是不容許某些內容,瀏覽器會阻止它並阻止您的網站受到潛在的攻擊。
使用CSP,您能夠肯定您的網站應包含哪些內容以及不包含哪些內容。
Content-Security-Policy: default-src 'self'; script-src 'self' just-comments.com www.google-analytics.com production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just-comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame-ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'
複製代碼
上面的規則集是我爲個人我的網站發佈的規則集,若是您認爲這個CSP示例定義很是難以提出 - 您徹底正確。 在個人我的網站上實施CSP規則集讓我嘗試了三次嘗試。 我部署它並回滾,由於它屢次打破了個人網站。 有一種更好的方法能夠作到這一點。
爲避免破壞您的網站,CSP還提供僅限報告的選項。
Content-Security-Policy-Report-Only: default-src 'self'; ... report-uri https://stefanjudis.report-uri.com/r/d/csp/reportOnly
複製代碼
使用Content-Security-Policy-Report-Only模式瀏覽器僅將阻止的資源記錄到控制檯而不是阻止它們。 此報告機制爲您提供了檢查和調整規則集的方法。
兩個標題,Content-Security-Policy和Content-Security-Policy-Report-Only,還提供了一種定義端點以將違規和日誌信息發送到(report-uri)的方法。 您能夠設置日誌記錄服務器並使用發送的日誌信息來調整CSP規則,直到它準備好上線。
建議的過程是:首先僅在報告模式下部署CSP,使用實際流量分析傳入的違規行爲,而且只有在再也不出現違反受控資源的狀況下才會啓用它。
若是您正在尋找能夠幫助您處理這些日誌的服務,我正在使用Report URI,它會很好的幫助你。
目前,瀏覽器對CSP的支持很好,但不幸的是,沒有多少網站在使用它。 要查看有多少網站使用CSP提供內容,我在HTTP Archive上運行了一個查詢,發現只有6%的已爬網站點使用CSP。 我認爲咱們能夠作得更好,使網絡更安全,避免咱們的用戶在不知情的狀況下挖掘加密貨幣。
在我寫這篇文章的時候,我在家裏使用個人快速Wi-Fi鏈接坐在一臺相對較新的MacBook前面。 開發人員常常忘記這樣的設置不是咱們大多數用戶的默認設置。 訪問咱們網站的人使用的是舊手機,而且處於糟糕的鏈接狀態。 擁有數百個請求的繁重和臃腫的網站給他們帶來了糟糕的體驗。
這不只僅是關於體驗的。 人們根據他們居住的地點爲數據支付不一樣的金額。 想象一下,你正在創建一個醫院網站。 有關此特定網站的信息可能對人們相當重要而且能夠挽救生命。
若是醫院網站上的頁面是5MB,那麼它不只速度慢,並且對於最須要它的人來講也可能太昂貴。 與非洲5MB數據的價格相比,歐洲或美國的5MB價格可有可無。 開發人員有責任讓每一個人都能負擔得起網絡。 這個職責包括提供正確的資源,評估正確使用的工具(你真的須要一個登錄頁面的JS框架嗎?),以及避免請求。
今天的網站很容易包含數百種資源,從樣式表到腳本文件再到圖像。 使用Cache-Control標頭,開發人員能夠定義資源應被視爲「新鮮」多長時間,而且能夠從瀏覽器緩存中提供。
Cache-Control: max-age=30, public
複製代碼
經過設置適當的Cache-Control,能夠保存數據傳輸,而且能夠從瀏覽器緩存中使用文件必定的秒數(max-age)。 瀏覽器應在時間跨度結束後從新驗證緩存的資源。
可是,當訪問者刷新頁面時,瀏覽器仍會從新驗證包含引用資源的頁面,以確保緩存的數據仍然有效。 服務器以304標頭響應,表示緩存的數據仍然良好,或200服務於更新的數據。 這能夠節省傳輸的數據,但不必定是請求。
這是 immutable 特徵發揮做用的地方。
在現代前端應用程序中,樣式表和腳本文件一般具備惟一的文件名,如styles.123abc.css。 此文件名取決於特定文件的內容。 當這些文件的內容發生更改時,會生成不一樣的文件名。
這些惟一文件可能會被永久緩存,包括用戶刷新頁面時的狀況。 不可變特徵能夠告訴瀏覽器不要在特定時間範圍內從新驗證資源。 這對指紋驗證的資源頗有意義,有助於避免從新驗證請求。
Cache-Control: max-age=31536000, public, immutable
複製代碼
最佳緩存很是困難,特別是瀏覽器緩存不是很直觀,由於它提供了多種配置。 我建議您查看如下資源:
使用 Cache-control,咱們能夠保存請求並減小重複經過線路傳輸的數據量。 咱們不只能夠保存請求,還能夠縮小轉移的內容。
在提供資源時,開發人員應確保儘量少地發送數據。 對於像HTML這樣的基於文本的資源,CSS和JavaScript壓縮在保存傳輸數據方面起着重要做用。
目前最經常使用的壓縮是GZIP。 服務器足夠快,能夠動態壓縮文本文件,並在請求時提供壓縮數據。 GZIP再也不是最好的選擇了。
若是您檢查瀏覽器對基於文本的文件(如HTML,CSS和JavaScript)所作的請求,並查看請求標頭,您將找到accept-encoding Header。
Accept-Encoding: gzip, deflate, br
複製代碼
此標頭告訴服務器它理解的壓縮算法。 不太知名的br表明是 Brotli(一種壓縮算法),是谷歌和Facebook等高流量網站使用的壓縮。 要使用Brotli,您的網站必須在HTTPS上運行。
此壓縮算法在建立時考慮了小文件大小。 當您在本地計算機上試一試並手動壓縮文件時,您會發現Brotli確實比GZIP壓縮得更好。
您可能據說Brotli壓縮也會變慢。 緣由是Brotli有11種壓縮模式,而且選擇默認模式以保證較小的文件大小,從而致使編碼時間較長。 另外一方面,GZIP有9種模式,而且考慮到速度和文件大小,選擇默認模式。
此決定使得Brotli的默認模式不適合進行即時壓縮,但若是更改壓縮模式,您能夠實現更小的文件大小,速度與GZIP至關。 您甚至可使用它進行即時壓縮,並將其視爲支持瀏覽器的潛在GZIP替代品。
除此以外,若是您想得到最大的文件節省,您可能會忘記在構建過程當中使用zopfli和Brotli文件動態壓縮文件和預生成優化的GZIP文件以靜態地爲它們提供服務的想法。
若是您想了解更多關於Brotli壓縮以及它與GZIP的比較,Akamai的人們圍繞這一主題進行了普遍的研究。
優化文本資產很是適合保存千字節,可是像圖像這樣的較重資源能夠節省更多數據。
瀏覽器不只告訴咱們他們理解的壓縮算法。 當您的瀏覽器請求圖像時,它還會提供有關其理解的文件格式的信息。
Accept: image/webp, image/apng, image/*,*/*;q=0.8
複製代碼
圍繞新圖像格式的競爭已經持續了幾年,但如今看起來像webp贏了。 Webp是Google發明的一種圖像格式,目前對webp圖像的支持很是好。
使用此請求標頭,即便瀏覽器請求image.jpg致使文件較小,開發人員也能夠提供 **webp **圖像。 Dean Hume寫了一篇關於如何在服務工做者中作這件事的好指南。 那太酷了!
您還能夠啓用客戶端提示以支持瀏覽器。 客戶端提示是一種告訴瀏覽器發送附加標題的方法,這些標題提供有關視口寬度,圖像寬度甚至網絡條件的信息,如RTT(往返時間)和鏈接類型(如2g)。
您能夠經過包含元元素來啓用它們:
<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink">
<meta http-equiv="Accept-CH-Lifetime" content="86400">
複製代碼
或者在初始HTML請求上設置標題:
Accept-CH: Width, Viewport-Width
Accept-CH-Lifetime: 100
複製代碼
支持瀏覽器將開始在如下請求中發送定義的時間跨度(Accept-CH-Lifetime,以秒爲單位)的附加信息,這些請求能夠幫助開發人員根據用戶條件定製示例圖像,而無需更改任何HTML。
要在服務器端接收例如圖像寬度等附加信息,您能夠爲圖像配備尺寸屬性,以便爲瀏覽器提供有關如何佈置圖像的其餘信息。
<!-- this images is laid over the full width | 100 viewport width -->
<img class="w-100" src="/img/header.jpg" alt="" sizes="100vw">
複製代碼
使用最初收到的Accept-CH響應標題和配備了支持瀏覽器的sizes屬性的圖像將在圖像請求中包含視口寬度和寬度標題,告訴您哪一個圖像最適合。
<picture>
<!-- serve WebP to Chrome, Edge, Firefox and Opera -->
<source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w, /image/thing-800.webp 800w, /image/thing-1200.webp 1200w, /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w" type="image/webp">
<source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w, /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w, /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w" type="image/webp">
<!-- serve JPEG to others -->
<source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w, /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w, /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w">
<source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w, /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w, /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w">
<!-- fallback for browsers that don't support picture -->
<img src="/image/thing.jpg" width="50%">
</picture>
複製代碼
經過訪問視口寬度和圖像大小的可能性,您能夠將資產調整大小邏輯移動到服務器的中心位置。
你必須考慮,只是由於你手頭有準確的圖像寬度,你不想爲每一個寬度建立圖像。 發送特定維度範圍(image-200,image-300,...)的圖像有助於利用CDN緩存並節省計算時間。
此外,利用服務工做者等當前技術,您甚至能夠在客戶端中攔截和更改請求以提供最佳圖像文件。 經過啓用的客戶端提示,服務工做人員能夠訪問佈局信息,並結合圖像API(例如Cloudinary),您能夠在瀏覽器中調整圖像URL以接收正確大小的圖像。
若是您正在尋找有關客戶提示的更多信息,能夠查看Jeremy Wagner的文章或Ilya Grigorik關於該主題的文章。
咱們全部人天天都要上網幾個小時,我認爲最後一個方面很是重要 - 網絡必須尊重他人。
做爲開發人員,咱們但願確保重視用戶的時間。 沒人想浪費時間。 如前面部分所述,提供正確的數據在節省時間和數據方面發揮着重要做用。 這不只是關於提出的請求,還關於這些請求的時間和順序。
讓咱們想一個例子:若是您在網站中包含樣式表,瀏覽器在加載以前不會顯示任何內容。 雖然沒有顯示任何內容,但瀏覽器仍會繼續解析HTML以查找要獲取的其餘資源。 加載和解析樣式表時,它可能包含對其餘關鍵資源的引用,例如必須請求的字體。 此順序過程能夠增長訪問者的加載時間。
使用rel = preload,您能夠向瀏覽器提供有關在不久的未來請求的資源的信息。
您能夠經過HTML元素預加載資源:
<link rel="preload" href="/font.woff2" as="font" type="font/woff2" crossorigin="anonymous">
複製代碼
或者是Headers:
Link: </font.woff2>; rel=preload; as=font; no-push
複製代碼
這樣,瀏覽器接收標頭或發現連接元素並當即請求資源,以便在須要時它們已經位於瀏覽器緩存中。 此過程重視訪問者的時間。
要以最佳方式預加載資源並瞭解全部配置,我建議您查看如下資源:
若是最後有一件事我不想再看到,那就是網站平白無故地要求我得到權限。 我只能引用個人同事菲爾納什的話題。
**不要求頁面加載的通知權限。
**
開發人員應該尊重訪問者,不要創建惹惱訪問者的網站。 人們只需單擊全部權限對話框便可。 網站和開發人員失去了不少信任,若是咱們開發人員沒有仔細使用它們,那麼全部新的閃亮網頁功能都會失去力量。
可是,若是您的站點必須包含大量第三方代碼而且全部這些腳本會觸發一個又一個的權限對話,該怎麼辦? 如何確保全部包含的腳本都表現出來?
這是Feature-Policy Header發揮做用的地方。 使用此標頭,您能夠定義容許的功能,並限制可能由您網站中運行代碼的其餘人觸發的彈出權限對話框。
Feature-Policy: vibrate 'none'; geolocation 'none'
複製代碼
您可使用標頭爲您的網站定義它,但也能夠爲嵌入式內容定義它,例如iframe,這對於第三方集成是必需的。
<iframe allow="camera 'none'; microphone 'none'">
複製代碼
在撰寫本文時,功能策略具備很高的實驗性,但若是你看看即將推出的選項,那就很是使人興奮了。 在不久的未來,開發人員不只能夠限制本身並防止惱人的對話框的傳輸,還可能阻止非優化的媒體。 這些功能將在用戶體驗方面產生重大影響。
查看上面的功能策略列表,您可能想知道最煩人的一次推送通知發生了什麼。 事實證實推送通知的功能策略的實現比預期更難。 若是您想了解更多信息,能夠按照提交的GitHub issues 進行操做。
使用功能政策,您能夠確保您和您的第三方不會將您的網站變成許可解僱競賽,遺憾的是,這種競爭已經成爲當今許多網站的默認狀態。
在本文中,我只介紹了一些有助於改善用戶體驗的標題。 若是你想看到幾乎完整的標題及其可能性的概述,我能夠推薦看看Christian Schaefer的幻燈片「HTTP標題 - 隱藏的冠軍」。
我知道今天創建一個偉大的網站是很是具備挑戰性的。 開發人員必須考慮設計,設備,框架,以及是......標題也起做用。 但願本文給出了一些想法,您將在下一個Web項目中考慮安全性,可負擔性和尊重,由於這些因素使Web真正適合每一個人。