這篇筆記是接續前一篇筆記的內容,摘要自前端三十 從HTML到瀏覽器渲染的前端開發者必備心法,原書內容出自作者鐵人賽的文章。
瀏覽器
跨瀏覽器差異解決工具
- Autoprefixer: Browserslist 設定要支援的瀏覽器版本
- Polyfill
- Babel
從輸入網址到取得網頁資源過程
- 輸入網址
- 瀏覽器解析網址
- Protocol 通訊協定:HTTP、HTTPS
- Domain 網域
- Path 路徑
- 瀏覽器請求DNS查詢此網址對應的伺服器IP位址
- 為避免重複查詢造成大量成本,可透過以下步驟加速查詢
- 檢查本地 DNS Cache
- 檢查電腦 .host 檔案
- 以上找不到才向 DNS 送出查詢IP的請求
- 與該IP伺服器建立連線(TCP三向交握)
- 伺服器根據瀏覽器請求(IP、埠號(port)、路由等)打包成封包經由TCP連線傳輸
- HTTPS 通訊協定連線:會建立TLS加密連線。
- 伺服器接收請求,拆開封包、檢查封包資訊送給應用程式處理這些請求(查詢資料庫、資料處理等),並準備給予回應。
- SSR
- SPA
- 伺服器將處理好的請求回應給瀏覽器端應用程式。
- 解析HTML結構,依照頁面內容持續向後端發送請求資源;
- \ 依狀況直接或背景下載 JavaScript 檔案,也可能取用快取避免下載會耗時耗資源;
- 頁面解析完成才會開始渲染畫面:HTML解析成DOM Tree、CSS解析成CSSOM Tree,合併兩者變成Render Tree,並且計算瀏覽器範圍每個像素的內容才繪製畫面。
網頁開發
前後端分離
早期的SSR
- Spaghetti code 麵條式代碼
- 前後端在同一份檔案
- JSP (Java Server Page)
MVC
- 資料與UI分離
- 架構
- Model 模型: 處理資料、演算法、商業邏輯
- View 視圖: 畫面
- Controller 控制器: 控制、處理使用者請求
- 未解決的問題
- 頁面由伺服器產生,每次更新頁面需要全頁重新渲染
- 伺服器取得資料、計算和送出相應的畫面結構需要龐大運算和流量
SPA
- 伺服器提供引入JS的檔案,其餘取得資料、處理畫面、頁面跳轉交給JS處理
- Gmail: XMLHttpRequest
- 優點
- Server不需處理MVC中的view:降低伺服器運算效能
- 缺點
- 空白畫面:第一步取得用於載入JS的空白HTML,等待JS下載完成才計算、渲染畫面,網速較慢地區可能要等待一段時間才看到畫面
- SEO (Search Engine Optimization) 搜尋引擎最佳化
- 前後端分離的MVC:在前端也改成MVC架構處理畫面
- Awesome JavaScript
Isomorphic/ Universal JavaScript
- 第一頁SSR + CSR(Client-Side Rendering)
- 伺服器先計算送出首頁
- 其他畫面由JS處理
- 可能的問題:同個畫面前後端都要作一次
- Node.js 出現:同份JS code處理前後端
- 前端框架再包裹一層SSR:React's Next、Vue's Nuxt
- 其他解決第一頁問題的工具
- Prerender:事先計算會被使用者直接連結的各個頁面
- 補充資了
打包
打包優點
- 程式碼轉譯
- 程式碼優化
- 加速開發
- Webpack - Spritesmith: 圖檔合併
- Webpach - Dev Server
打包工具
- Grunt
- Gulp
- Webpack
- Rollup
- Backpack
- Parcel
跨域請求
跨域請求問題:開發者透過JS對不同於當前位置來源(如 domain、protocol、port)發送請求,請求的回應被瀏覽器阻擋。
解決方法
- JSONP: HTML的img、script、iframe標籤
- CORS(Cross-Origin Resource Sharing) 跨來源資源共用
- HTTP Header
- Access-Control-Allow-Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
- Simple request
- Preflighted request
- HTTP Header
- 代理伺服器(後端)
- 繞過瀏覽器的CORS限制
- nginx 實作反向代理伺服器
Cache
- 儲存已請求過的資料,避免重複取得的資料。
- 可作為快取:Web Storage API、CDN節點、伺服器儲存快取等
- 大部分還是由後端伺服器設定
- 前端可處理的:本地快取
本地快取
Header設定Cache-Control
- public
- private
- no-cache
- no-store
(可以加入 max-age 屬性)
ETag
Header設定ETag,即使快取有設定資源快取期限,但因為會確認檔案加上的Etag hash值沒有變動,並回傳304,表示檔案內容無變更,就能繼續沿用舊檔案。
檔名控制
每次修正後、輸出的檔案名稱加上hash值,讓瀏覽器取得不同檔名以為是全新資源,會忽略快取值接發送請求。
Cookie & Session
Cookie
- 儲存使用者資訊,讓瀏覽器得以辨識發送請求的使用者,給予相應的回應。
- Cookie 屬性
- domain
- path
- Max-Age
- Expires
- secure
- HttpOnly
- Cookie的使用限制
- 單一 Cookie 只能儲存4k大小的資訊
- 一個 domain 最多只能儲存20個 Cookies
- 所以 Cookies 不能儲存大量資訊、不能對目標網域的每個請求帶上 Cookies。
- 一般Cookie只會儲存使用者id,再去伺服器要此使用者id的狀態和資料。
- 資安風險:為避免被盜取使用者id,可以善用cookie的secure、HttpOnly屬性等。
Session
- 伺服器能辨識同一位使用者狀態的時間區間,例如使用者從登入到登出的時間、從開始瀏覽網頁到使用者失效。
SEO
Search Engine Land
HTML
- title
- meta
- description
- HTML5 - Syntax Tags 取代 div
- h1 ~ h6
- \
其他
- 手機版頁面
- HTTPS
- 在地、語意化網址
- 網站回應速度 ⇔ Isomorphic JS (Router)、後端
- SERP (Search Engine Results Pages):如客製每個頁面的結構化資料
- 搜尋引擎最佳化初學者指南
效能
- 載入資源
- 畫面渲染
載入資源
- 程式碼 minify+uglify
- 圖檔壓縮:不要放超過網頁尺寸的圖(imagecompressor.com)
- 只提供使用者必要的內容或只載入部分網頁內容(API取得資料)
- WebAPI: Intersection Observer API
- Cache、Web Storage
畫面渲染
- CSS
- 盡量使用樣式屬性變動取代排版屬性變動
- 圖層數量
- JS
- 讓出 Main Thread
- Web Worker 處理複雜、長時間計算
- 動畫:requestAnimationFrame
Backend
套件開發與管理
套件安裝資安問題
- 透過 Semantic Versioning (語意化版本) 指定版本
- package-lock.json、yarn.lock等lock檔放進版本控制管理內容
未來的套件管理工具:Tink
後端語言
Node.js
- JS由事件驅動,透過JS的事件迴圈機制,能讓執行緒幾乎不會卡住,適合接收高併發(High Concurrency)、高流量的請求。
- 作法就是將請求當作事件迴圈機制中的待處理事件,主執行緒只負責承接、轉拋、回應。
- Node.js 用 libuv 實現事件迴圈機制,且分成更多階段(可參考)
- 缺點:Node.js不適合商業邏輯複雜且效能瓶頸並非流量的服務。
網路
API
HTTP Method
- GET 取得
- HEAD 取得Header:通常測試資源是否存在、查看伺服器對資源的Header設定
- POST 新增、提交
- PUT 取代指定資源
- PATCH 修改指定資源
- DELETE 刪除指定資源
- OPTION 詢問與指定資源的溝通方法:常用於詢問資源如何獲取,常在發送CORS的預檢(preflighted)請求。
API 設計風格
- RESTFul API
- Resource Representational State Transfer (表現層狀態轉換)
- HTTP Methods + 目標資源(URI/URL) + 內容型態(HTML、XML、JSON等)
- 缺點:有依賴關係的巢狀資料可能要查找好幾層、需要查找多個資料才能堆砌出完整頁面。
- GraphQL
- 透過Schema定義資料,並藉由與JSON格式類似的查詢語句取得查詢結果。
- 特色:強型別、查詢句即文件、查詢句即回應的資料結構(不會有冗餘內容)、統一對外入口、可拼接查詢一併送出
- GraphQL 送出的都是 POST 請求,所以快取機制要另外實作。
- GraphQL + Apollo + 前端框架
- 缺點:複雜的資料串接邏輯都需寫在後端
實作
- 瀏覽器預設是以GET、HEAD做快取
- 如果取得資料不是用GET而是用POST,可能瀏覽器和中間代理伺服器不會對資源快取,必須由開發者自行用其他方式完成。
- SEO:如Google爬蟲會忽略需要透過POST取得的資源,避免POST意外或造成副作用
資訊安全
29. [WEB] 網站常見的資安問題有哪些?
XSS (Cross Site Scripting) / JavaScript Injection
- 被植入惡意程式碼
- 解決方法:避免直接運用使用者輸入的內容
- 關鍵字過濾、字元轉換
- 要注意的地方:表單輸入框、網址列參數、Cookies、Web Storage
- XSS Challenges
CSRF (Cross Site Request Forgery)
- 利用 Cookies、Session 認證機制,假冒使用者ID竊取資料的攻擊手法
- Check Referer:檢查Header Referer值、確認請求來源是自家或允許的服務
- CSRF Token:Cookie和請求的資料欄位都加上csrftoken讓後端檢查兩者是否為同數值
- SameSite Cookie:Cookie加上samesite屬性
SQL Injection
- 參數化查詢,避免使用者輸入的參數與查詢語句直接結合
- 輸入檢查
- 插入跳脫字元
- 嚴格設定應用程式權限
JSON Hijacking
- 獲得使用者權限呼叫API取得機密資料
- ES6 Proxy
- 可用避免CSRF攻擊的技巧來避免使用者被惡意取得權限
- for(;;);
小結較需加強的概念:
- JS變更畫面與Server計算、重新渲染畫面的差異?(SSR vs SPA)
- 資訊安全