<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Andy 的筆記</title>
  
  
  <link href="https://andyhung0723.github.io/atom.xml" rel="self"/>
  
  <link href="https://andyhung0723.github.io/"/>
  <updated>2026-11-12T16:00:00.000Z</updated>
  <id>https://andyhung0723.github.io/</id>
  
  <author>
    <name>Andy Hung</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>技術週報｜2026-11-09</title>
    <link href="https://andyhung0723.github.io/2026/11/09/tech-radar-2026-11-09/"/>
    <id>https://andyhung0723.github.io/2026/11/09/tech-radar-2026-11-09/</id>
    <published>2026-11-09T01:10:00.000Z</published>
    <updated>2026-11-12T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>2026&#x2F;11&#x2F;02–11&#x2F;08 的 20 則技術更新。11&#x2F;13 依官方公告複核；以下建議是適用條件與測試方向，不代表任何特定環境已受影響。</p><span id="more"></span><h2 id="01｜GitHub-Actions：公開專案的-pull-request-target-政策"><a href="#01｜GitHub-Actions：公開專案的-pull-request-target-政策" class="headerlink" title="01｜GitHub Actions：公開專案的 pull_request_target 政策"></a>01｜GitHub Actions：公開專案的 pull_request_target 政策</h2><p><strong>11&#x2F;02 公告｜12&#x2F;02 生效</strong></p><p>GitHub.com 公開 repository 的 <code>pull_request_target</code> 將預設遭封鎖，除非適用的 Actions event policy 明確允許。Private、internal repository 與 GitHub Enterprise Server 不在本次範圍。此事件能接觸 base repository 的權限與 secrets，執行 fork 的不可信程式碼尤其需要審慎。</p><p><strong>先做什麼：</strong> 搜尋 workflow 的觸發事件，查看 Actions Insights 的影響紀錄。優先評估 <code>pull_request</code>；必要例外應限縮到特定 workflow。兩次短暫強制測試為台灣時間 11&#x2F;10、11&#x2F;17 的 00:00–02:00，第一次已過。</p><p><a href="https://github.blog/changelog/2026-11-02-pull_request_target-blocked-by-default-december-2/">官方公告</a></p><h2 id="02｜Gemini-Code-Assist：既有綁定權益將結束"><a href="#02｜Gemini-Code-Assist：既有綁定權益將結束" class="headerlink" title="02｜Gemini Code Assist：既有綁定權益將結束"></a>02｜Gemini Code Assist：既有綁定權益將結束</h2><p><strong>11&#x2F;06 公告｜2027&#x2F;03&#x2F;31 截止</strong></p><p>既有 Gemini Enterprise Standard／Plus 訂閱附帶的 Code Assist 權益將於 2027&#x2F;03&#x2F;31 移除，在此之前僅支援 Gemini 3.x 模型系列。自 10&#x2F;09 起，新訂閱已不再附帶該權益；Google 提出 Antigravity 作為開發流程的遷移選項。</p><p><strong>先做什麼：</strong> 核對授權來源，再評估替代工具。這不是所有 Code Assist 授權都在同一天停用的公告，獨立訂閱需另查適用條款。</p><p><a href="https://docs.cloud.google.com/gemini/enterprise/docs/release-notes">Gemini Enterprise 發布紀錄</a></p><h2 id="03｜OpenTelemetry-JavaScript-SDK-3-0"><a href="#03｜OpenTelemetry-JavaScript-SDK-3-0" class="headerlink" title="03｜OpenTelemetry JavaScript SDK 3.0"></a>03｜OpenTelemetry JavaScript SDK 3.0</h2><p><strong>11&#x2F;05 發布</strong></p><p>最低 Node.js 版本提高至 22.15.0，停止支援 Node.js 18、20；改善 ESM／CommonJS 匯出，將 Logs API 納入 <code>@opentelemetry/api</code>，並整併 tracing SDK。部分舊相容套件與 API 移除。穩定版 SDK 2.x 在 3.0 發布後仍有一年支援。</p><p><strong>先做什麼：</strong> 盤點 Node.js runtime、exporter 與 <code>@opentelemetry/*</code> 相依版本，依 migration guide 測試 traces、metrics、logs。這次變更不要求 Python SDK 一併升級。</p><p><a href="https://opentelemetry.io/blog/2026/otel-js-sdk-3-0/">官方發布與遷移說明</a></p><h2 id="04｜Container-Optimized-OS：LTS-安全更新"><a href="#04｜Container-Optimized-OS：LTS-安全更新" class="headerlink" title="04｜Container-Optimized OS：LTS 安全更新"></a>04｜Container-Optimized OS：LTS 安全更新</h2><p><strong>11&#x2F;06 發布</strong></p><p>COS 125、129 發布 LTS refresh，包含系統與容器相關元件修正。COS 125 的映像版本為 <code>cos-125-19216-801-14</code>；實際漏洞清單、runtime 與 kernel 版本應依使用的 milestone 核對，不能跨映像套用。</p><p><strong>先做什麼：</strong> 查明主機 boot image，安排支援的更新與必要重啟，先驗證容器能正常啟動。Ubuntu、Debian 等其他映像不適用這份 COS 修補清單。</p><p><a href="https://docs.cloud.google.com/container-optimized-os/docs/release-notes/m125"> COS 125 發布紀錄</a> · <a href="https://docs.cloud.google.com/container-optimized-os/docs/release-notes/m129">COS 129 發布紀錄</a></p><h2 id="05｜API-Gateway：Streaming-backend-認證調整"><a href="#05｜API-Gateway：Streaming-backend-認證調整" class="headerlink" title="05｜API Gateway：Streaming backend 認證調整"></a>05｜API Gateway：Streaming backend 認證調整</h2><p><strong>11&#x2F;03 發布</strong></p><p>啟用 streaming 的 gateway，對主機名稱以 <code>.googleapis.com</code> 或 <code>.vertexai.goog</code> 結尾的 backend，改用 gateway service account 的 access token；其他 backend 仍接收 ID token。既有 gateway 會在平台下次更新，或切換新 API config 時套用。</p><p><strong>先做什麼：</strong> 使用 Vertex AI 等 Google API backend 的流程，應測試 token 類型、IAM 權限及更新後的認證結果。未使用 streaming gateway 者不必為此修改服務。</p><p><a href="https://docs.cloud.google.com/api-gateway/docs/release-notes">API Gateway 發布紀錄</a></p><h2 id="06｜Claude-Code-2-1-319：Auto-Mode-與-MCP-背景任務"><a href="#06｜Claude-Code-2-1-319：Auto-Mode-與-MCP-背景任務" class="headerlink" title="06｜Claude Code 2.1.319：Auto Mode 與 MCP 背景任務"></a>06｜Claude Code 2.1.319：Auto Mode 與 MCP 背景任務</h2><p><strong>11&#x2F;06 發布</strong></p><p>部分停用 telemetry／feature flag 或使用 LLM gateway 的 Auto Mode 情境，伺服器無法檢查的工具呼叫會改為詢問或拒絕，不再自動回退至內建分類器。Bedrock、Vertex、Foundry 的相關行為不變。新版也支援 MCP task 背景執行、<code>permissions.denyInsteadOfPrompting</code>，以及 <code>/claude-api latency-optimize</code>。</p><p><strong>先做什麼：</strong> 升級前測試非互動式流程的授權、MCP 任務完成通知與失敗恢復，不要為了讓流程跑完而全面放寬權限。</p><p><a href="https://github.com/anthropics/claude-code/releases/tag/v2.1.319">v2.1.319 release</a></p><h2 id="07｜Claude-API：IP-Allowlist-Beta"><a href="#07｜Claude-API：IP-Allowlist-Beta" class="headerlink" title="07｜Claude API：IP Allowlist Beta"></a>07｜Claude API：IP Allowlist Beta</h2><p><strong>11&#x2F;05 發布</strong></p><p>Claude Console 可設定組織層級的 IP allowlist，支援 IPv4、IPv6 與 CIDR，每組織最多 1,000 項。受涵蓋服務會拒絕清單以外的來源，降低 API key 外洩後可被使用的範圍；仍須確認服務涵蓋限制。</p><p><strong>先做什麼：</strong> 先盤點出口 IP，再測試固定 NAT 與來源限制。使用動態出口的工作負載若直接啟用清單，可能被自己擋下。</p><p><a href="https://platform.claude.com/docs/en/release-notes/overview">Claude Platform 發布紀錄</a></p><h2 id="08｜Agent-Registry：Skill-版本與安全治理-GA"><a href="#08｜Agent-Registry：Skill-版本與安全治理-GA" class="headerlink" title="08｜Agent Registry：Skill 版本與安全治理 GA"></a>08｜Agent Registry：Skill 版本與安全治理 GA</h2><p><strong>11&#x2F;06 發布</strong></p><p>Standalone skills 正式 GA，提供 <code>Skill</code>、不可變的 <code>SkillRevision</code>、publisher 資訊，以及註冊、搜尋與版本管理。安全掃描可產生 findings，搭配 Organization Policy 與 IAM 控制使用；skill payload 的 CMEK 保護仍為 Preview。</p><p><strong>先做什麼：</strong> 以少量共用 skills 測試版本固定、來源審核、掃描結果與最小權限。掃描通過不等於可免除人工檢查。</p><p><a href="https://docs.cloud.google.com/agent-registry/release-notes">Agent Registry 發布紀錄</a></p><h2 id="09｜Claude-Messages-API：Message-Threads-Beta"><a href="#09｜Claude-Messages-API：Message-Threads-Beta" class="headerlink" title="09｜Claude Messages API：Message Threads Beta"></a>09｜Claude Messages API：Message Threads Beta</h2><p><strong>11&#x2F;02 發布</strong></p><p>伺服器可暫存對話，後續請求只傳新增訊息，減少 payload 並改善首 token 延遲。使用 <code>message-threads-2026-08-12</code> beta header；thread 在最後請求後 5 分鐘過期，最後使用後最多 1 小時內刪除。</p><p><strong>先做什麼：</strong> 用多輪 tool calling 比較延遲、傳輸量及失敗恢復。它不是長期記憶或永久對話儲存。</p><p><a href="https://platform.claude.com/docs/en/release-notes/overview">Claude Platform 發布紀錄</a></p><h2 id="10｜Cloud-Run：Ephemeral-Disk-GA"><a href="#10｜Cloud-Run：Ephemeral-Disk-GA" class="headerlink" title="10｜Cloud Run：Ephemeral Disk GA"></a>10｜Cloud Run：Ephemeral Disk GA</h2><p><strong>11&#x2F;04 發布</strong></p><p>Cloud Run ephemeral disk 已正式 GA，可在 service、job 或 worker pool 掛載只存續於該 instance 生命週期的磁碟 volume。適合文件轉換、批次作業或其他中間產物，不是永久儲存。</p><p><strong>先做什麼：</strong> 測試容量、效能、費用及 instance 結束後的資料處理。需要持久化的成果應另存 Cloud Storage 或資料庫。</p><p><a href="https://docs.cloud.google.com/run/docs/release-notes">Cloud Run 發布紀錄</a></p><h2 id="11｜OpenAI：GPT-6-Cyber"><a href="#11｜OpenAI：GPT-6-Cyber" class="headerlink" title="11｜OpenAI：GPT-6 Cyber"></a>11｜OpenAI：GPT-6 Cyber</h2><p><strong>11&#x2F;05 發布</strong></p><p>API changelog 新增 <code>gpt-6-cyber</code>，用途包括漏洞調查、在已授權測試環境重現問題，以及驗證修補。首次使用前需閱讀 Daybreak 設定與存取要求。</p><p><strong>先做什麼：</strong> 先確認資格與授權範圍，再用隔離測試環境評估結果。模型產出不能取代人工驗證，也不應直接對未授權系統執行測試。</p><p><a href="https://developers.openai.com/api/docs/changelog">OpenAI API Changelog</a></p><h2 id="12｜Codex-CLI-0-167-0：Agent-Command-Center"><a href="#12｜Codex-CLI-0-167-0：Agent-Command-Center" class="headerlink" title="12｜Codex CLI 0.167.0：Agent Command Center"></a>12｜Codex CLI 0.167.0：Agent Command Center</h2><p><strong>11&#x2F;06 發布</strong></p><p>新增 <code>codex agents --no-daemon</code>，可在 command center 與 session picker 辨識未讀結果、切換 backend，並在支援的終端機預覽本機圖片。實驗性的 <code>gcp_setup_wizard</code> 協助設定 Vertex AI 的 ADC 或憑證檔案。</p><p><strong>先做什麼：</strong> 測試多 backend 切換、對話恢復與認證權限。這是 CLI 版本更新，不代表每項功能都已同步到桌面 App。</p><p><a href="https://github.com/openai/codex/releases/tag/rust-v0.167.0">0.167.0 release</a></p><h2 id="13｜Gemini-CLI-0-67-0：MCP-權限與-Sandbox-修正"><a href="#13｜Gemini-CLI-0-67-0：MCP-權限與-Sandbox-修正" class="headerlink" title="13｜Gemini CLI 0.67.0：MCP 權限與 Sandbox 修正"></a>13｜Gemini CLI 0.67.0：MCP 權限與 Sandbox 修正</h2><p><strong>11&#x2F;04 發布</strong></p><p>新增 <code>models</code> 指令與 <code>--list-models</code>，改善容器 sandbox 的 IDE companion 連線，修正唯讀檔案／hard link 寫入處理，以及非互動模式取消後仍繼續執行工具的問題。ACP 權限請求現在包含 MCP server 與 tool metadata。</p><p><strong>先做什麼：</strong> 測試檔案保護、取消行為和 MCP 授權畫面，尤其是把 CLI 接入自動化的流程。</p><p><a href="https://github.com/google-gemini/gemini-cli/releases/tag/v0.67.0">v0.67.0 release</a></p><h2 id="14｜Copilot-Code-Review：API-管理與來源追蹤"><a href="#14｜Copilot-Code-Review：API-管理與來源追蹤" class="headerlink" title="14｜Copilot Code Review：API 管理與來源追蹤"></a>14｜Copilot Code Review：API 管理與來源追蹤</h2><p><strong>11&#x2F;06 發布</strong></p><p>REST／GraphQL API 擴充到企業、組織與 repository 的 code review 設定，並能辨識 Copilot review／comment、review effort，以及回報的 skills、MCP、自訂指令來源。不同管理層級的權限不同；企業與組織設定端點尚不支援 GitHub App 或 fine-grained PAT。</p><p><strong>先做什麼：</strong> 用測試 repository 比較審查品質、誤報與人工修改時間，再決定是否擴大使用。來源資訊是可追蹤線索，不是結果正確性的保證。</p><p><a href="https://github.blog/changelog/2026-11-06-copilot-code-review-api-management-and-review-overview-updates/">GitHub 官方公告</a></p><h2 id="15｜Dependabot：支援-Agent-Package-Manager"><a href="#15｜Dependabot：支援-Agent-Package-Manager" class="headerlink" title="15｜Dependabot：支援 Agent Package Manager"></a>15｜Dependabot：支援 Agent Package Manager</h2><p><strong>11&#x2F;03 發布</strong></p><p>Dependabot 可更新 <code>apm.yml</code> 中受支援的 git 相依項目，並在存在時重建 <code>apm.lock.yaml</code>，將 skills、prompts、instructions 的版本更新納入 PR。這次支援的是版本更新，<strong>不包含安全漏洞更新</strong>。</p><p><strong>先做什麼：</strong> 有使用 APM 才需要新增對應設定；先驗證 lockfile 與審核流程，勿把自動更新 PR 視為相依內容已通過安全審查。</p><p><a href="https://github.blog/changelog/2026-11-03-dependabot-version-updates-support-agent-package-manager/">GitHub 官方公告</a></p><h2 id="16｜Pydantic-2-14-3：Serialization-與相容性修正"><a href="#16｜Pydantic-2-14-3：Serialization-與相容性修正" class="headerlink" title="16｜Pydantic 2.14.3：Serialization 與相容性修正"></a>16｜Pydantic 2.14.3：Serialization 與相容性修正</h2><p><strong>版本日期 11&#x2F;04；GitHub release 顯示 11&#x2F;05</strong></p><p>修正序列資料逐索引使用 <code>include</code>／<code>exclude</code> 時的平方級 serialization 時間，並改善 schema generation 與序列化效能。GraalPy wheel 也有調整：不再發布 3.11 wheel，改提供 3.13，並保留既有 3.12。</p><p><strong>先做什麼：</strong> 用代表性的巢狀資料與大型 API response 跑 benchmark，核對驗證結果與 JSON Schema。效能改善需以實際資料量測，不能直接當作所有 API 都會加速。</p><p><a href="https://github.com/pydantic/pydantic/releases/tag/v2.14.3">v2.14.3 release</a></p><h2 id="17｜Angular-22-2-5：Forms、Router-與-Resource"><a href="#17｜Angular-22-2-5：Forms、Router-與-Resource" class="headerlink" title="17｜Angular 22.2.5：Forms、Router 與 Resource"></a>17｜Angular 22.2.5：Forms、Router 與 Resource</h2><p><strong>11&#x2F;06 發布</strong></p><p><code>rxResource</code> 新增 <code>debugName</code>；自訂 <code>FormValueControl</code> 改善 <code>updateOn: blur</code>／<code>submit</code>，修正 required validator 對應與 router 的 <code>focusReset</code> 處理。圖片、影片的 <code>src</code> 為 null／undefined 時，也調整屬性移除行為。</p><p><strong>先做什麼：</strong> Angular 22 專案應測試表單控制項、導航焦點及 resource 行為。舊 major 版本仍需依完整升級指南處理，不宜只為這次 patch 跨版升級。</p><p><a href="https://github.com/angular/angular/releases/tag/v22.2.5">v22.2.5 release</a></p><h2 id="18｜Secret-Scanning：新增偵測器、減少誤報"><a href="#18｜Secret-Scanning：新增偵測器、減少誤報" class="headerlink" title="18｜Secret Scanning：新增偵測器、減少誤報"></a>18｜Secret Scanning：新增偵測器、減少誤報</h2><p><strong>11&#x2F;05 發布</strong></p><p>GitHub 新增 Starlink API secret 偵測，SpaceX 加入合作夥伴計畫。Google Cloud Storage、AWS、Alibaba、OpenVSX、Pydantic Logfire、Tencent 等偵測器改善誤報過濾；這不代表涵蓋所有雲端憑證。</p><p><strong>先做什麼：</strong> 確認適用的 Secret Scanning 與 Push Protection 設定，追查尚未處理的外洩告警。正式憑證仍應放在 secret manager，已外洩的金鑰需撤銷或輪替。</p><p><a href="https://github.blog/changelog/2026-11-05-secret-scanning-upgrades-detectors-adds-spacex-as-partner/">GitHub 官方公告</a></p><h2 id="19｜Copilot-Usage-API：區分-BYOK-與企業自訂模型"><a href="#19｜Copilot-Usage-API：區分-BYOK-與企業自訂模型" class="headerlink" title="19｜Copilot Usage API：區分 BYOK 與企業自訂模型"></a>19｜Copilot Usage API：區分 BYOK 與企業自訂模型</h2><p><strong>11&#x2F;03 公告</strong></p><p>用量報表可分開辨識本機 BYOK、企業自訂模型與 Copilot 託管模型。本機 BYOK 資料依賴 client telemetry，停用遙測或 provider 不回報 token 時會低估；企業自訂模型為伺服器側統計，沒有相同限制。</p><p><strong>先做什麼：</strong> 整合成本報表時標明資料缺口，避免把未回報用量當成零，也不要把不同付費來源混在一起比較。</p><p><a href="https://github.blog/changelog/2026-11-04-byok-and-enterprise-custom-models-in-the-copilot-usage-api/">GitHub 官方公告</a></p><h2 id="20｜GPT-Image-2-6：SVG-與動畫-GIF"><a href="#20｜GPT-Image-2-6：SVG-與動畫-GIF" class="headerlink" title="20｜GPT-Image-2.6：SVG 與動畫 GIF"></a>20｜GPT-Image-2.6：SVG 與動畫 GIF</h2><p><strong>11&#x2F;04 發布</strong></p><p><code>gpt-image-2.6-sunburst</code>、<code>gpt-image-2.6-flare</code> 支援圖片生成／編輯、可調整 complexity，以及 SVG、動畫 GIF 生成。受支援的 GPT-Image-2.5／2.6 模型也擴充 markup-guided editing。</p><p><strong>先做什麼：</strong> 比較文字正確率、SVG 可編輯性、GIF 穩定性、生成時間與成本。將產物放進網頁前仍需檢查格式與內容，不直接信任生成的標記。</p><p><a href="https://developers.openai.com/api/docs/changelog">OpenAI API Changelog</a></p><h2 id="後續追蹤"><a href="#後續追蹤" class="headerlink" title="後續追蹤"></a>後續追蹤</h2><p>先處理有截止日的 GitHub Actions 政策與授權變更，再安排 SDK／CLI 相容性測試。Agent Registry、IP allowlist、AI code review 則適合先用小型測試專案驗證，不必一次全面導入。</p><p>本期另追蹤 FastAPI、Gemini API、MCP／A2A 與 RAG／evaluation，原週報未選出額外獨立消息；這不表示這些專案完全沒有更新。Cloud Run 的 Python 3.15 runtime 已於 11&#x2F;02 進入 Preview，但不代表既有 Python 服務需要立即升級。</p><h2 id="到期與生效日期"><a href="#到期與生效日期" class="headerlink" title="到期與生效日期"></a>到期與生效日期</h2><p>以下包含先前已公告的時程，並非全是本週新消息。日期狀態以 11&#x2F;13 複核為準。</p><table><thead><tr><th>日期</th><th>項目</th><th>檢查方向</th></tr></thead><tbody><tr><td>11&#x2F;10 00:00–02:00（台灣，已過）</td><td>GitHub Actions 第一次短暫封鎖測試</td><td>查看失敗紀錄</td></tr><tr><td>11&#x2F;17 00:00–02:00（台灣）</td><td>GitHub Actions 第二次短暫封鎖測試</td><td>確認 trigger 與必要例外</td></tr><tr><td>11&#x2F;28</td><td>Angular 20 LTS 結束</td><td>規劃受支援版本遷移</td></tr><tr><td>11&#x2F;30</td><td>Claude Sonnet 4.5 在 Claude API 退役</td><td>查找舊 model ID</td></tr><tr><td>11&#x2F;30</td><td>Claude Opus 4.8 fast mode 移除</td><td>檢查 <code>speed: &quot;fast&quot;</code>，不等同整個模型退役</td></tr><tr><td>12&#x2F;02</td><td>GitHub Actions 新政策生效</td><td>完成公開 workflow 相容性檢查</td></tr><tr><td>2027&#x2F;03&#x2F;31</td><td>Gemini Enterprise 既有綁定 Code Assist 權益結束</td><td>核對授權來源與替代方案</td></tr></tbody></table><p>來源：<a href="https://angular.dev/reference/releases">Angular 支援時程</a>、<a href="https://platform.claude.com/docs/en/release-notes/overview">Claude 發布紀錄</a>，以及第 01、02 則官方公告。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;2026&amp;#x2F;11&amp;#x2F;02–11&amp;#x2F;08 的 20 則技術更新。11&amp;#x2F;13 依官方公告複核；以下建議是適用條件與測試方向，不代表任何特定環境已受影響。&lt;/p&gt;</summary>
    
    
    
    <category term="技術雷達" scheme="https://andyhung0723.github.io/categories/%E6%8A%80%E8%A1%93%E9%9B%B7%E9%81%94/"/>
    
    
    <category term="GitHub Actions" scheme="https://andyhung0723.github.io/tags/GitHub-Actions/"/>
    
    <category term="CI/CD" scheme="https://andyhung0723.github.io/tags/CI-CD/"/>
    
    <category term="DevOps" scheme="https://andyhung0723.github.io/tags/DevOps/"/>
    
    <category term="AI" scheme="https://andyhung0723.github.io/tags/AI/"/>
    
    <category term="Python" scheme="https://andyhung0723.github.io/tags/Python/"/>
    
    <category term="GCP" scheme="https://andyhung0723.github.io/tags/GCP/"/>
    
  </entry>
  
  <entry>
    <title>資安週報｜2026/11/09</title>
    <link href="https://andyhung0723.github.io/2026/11/09/security-weekly-2026-11-09/"/>
    <id>https://andyhung0723.github.io/2026/11/09/security-weekly-2026-11-09/</id>
    <published>2026-11-09T01:00:00.000Z</published>
    <updated>2026-11-12T16:00:00.000Z</updated>
    
    <content type="html"><![CDATA[<p>整理 2026&#x2F;11&#x2F;02–11&#x2F;08 的 14 個資安主題與其他平台追蹤結果。11&#x2F;13 重新核對官方來源，修正 Chrome 修補數量，補上 PostgreSQL 14 的最新版本資訊。</p><p>優先確認 APT 修補；使用 WordPress 或 SonicWall 的環境，應先處理已知遭利用的漏洞。以下是通用盤點建議，不代表任何個別系統已受影響或已完成修補。</p><span id="more"></span><h2 id="1-APT：下載驗證繞過，可取得-root-權限"><a href="#1-APT：下載驗證繞過，可取得-root-權限" class="headerlink" title="1. APT：下載驗證繞過，可取得 root 權限"></a>1. APT：下載驗證繞過，可取得 root 權限</h2><p><strong>CVE-2026-109518｜11&#x2F;04｜Canonical：High，CVSS 4.0 7.7</strong></p><p>能操縱套件下載 HTTP 流量的攻擊者，可利用重新導向、下載重試與 hard link 處理缺陷，使 APT 安裝未驗證的套件。Debian 12、Ubuntu 22.04 起預設啟用下載重試；舊版也須檢查 <code>Acquire::Retries</code> 是否非零。</p><table><thead><tr><th>系統</th><th>APT 修補版本</th></tr></thead><tbody><tr><td>Debian 12</td><td><code>2.6.2</code></td></tr><tr><td>Debian 13</td><td><code>3.0.4</code></td></tr><tr><td>Ubuntu 22.04</td><td><code>2.4.15ubuntu0.1</code></td></tr><tr><td>Ubuntu 24.04</td><td><code>2.8.4ubuntu0.1</code></td></tr><tr><td>Ubuntu 26.04</td><td><code>3.2.1ubuntu0.1</code></td></tr><tr><td>Ubuntu 26.10</td><td><code>3.3.3ubuntu0.1</code></td></tr></tbody></table><p>Ubuntu 20.04 及更舊版本的修補取得方式涉及 Ubuntu Pro／Legacy，須對照公告。先確認已安裝版本，再依維護流程更新。HTTPS 可保護這條下載路徑，但不應取代正式修補。本次未確認野外利用。</p><p>來源：<a href="https://ubuntu.com/blog/apt-vulnerability-fixes-available">Canonical 說明</a>、<a href="https://ubuntu.com/security/notices/USN-8996-1">USN-8996-1</a>、<a href="https://security-tracker.debian.org/tracker/CVE-2026-109518">Debian Tracker</a>。</p><h2 id="2-WordPress：更新期間的遠端程式碼執行"><a href="#2-WordPress：更新期間的遠端程式碼執行" class="headerlink" title="2. WordPress：更新期間的遠端程式碼執行"></a>2. WordPress：更新期間的遠端程式碼執行</h2><p><strong>CVE-2026-119977｜11&#x2F;03 列入 CISA KEV</strong></p><p>WordPress 更新流程的競爭條件可能讓攻擊者在升級期間執行程式碼。7.1.4 已於 10&#x2F;28 修補；本週的新進展是確認實際利用，而不是首次發布修補。</p><p>有部署 WordPress 時，確認已安裝 7.1.4 或所屬舊分支的對應安全更新，並檢查更新期間的異常存取。不要只確認主站，測試站與活動網站也應納入盤點。</p><p>來源：<a href="https://wordpress.org/news/2026/10/wordpress-7-1-4/">WordPress 7.1.4</a>、<a href="https://www.cyber.gc.ca/en/alerts-advisories/wordpress-security-advisory-av26-1117">加拿大網路安全中心 AV26-1117</a>。</p><h2 id="3-SonicWall：SSL-VPN-驗證繞過"><a href="#3-SonicWall：SSL-VPN-驗證繞過" class="headerlink" title="3. SonicWall：SSL VPN 驗證繞過"></a>3. SonicWall：SSL VPN 驗證繞過</h2><p><strong>CVE-2026-19868｜11&#x2F;06 列入 CISA KEV</strong></p><p>這項 SonicOS SSL VPN 漏洞涉及驗證流程，原報告追蹤的是 SAML／MFA 繞過風險。加拿大網路安全中心確認 SonicWall 已表示漏洞遭到利用，並列出 <code>7.3.4-7013</code>、<code>8.2.2-8015</code> 的修補門檻。</p><p>應優先確認設備所屬分支、實際版本、VPN 對外暴露與異常登入紀錄。各機型及設定適用性仍以原廠公告為準；本次未能讀取原廠動態頁面的完整條件，因此不沿用原報告的 CVSS 數字。</p><p>來源：<a href="https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2026-0014">SonicWall SNWLID-2026-0014</a>、<a href="https://www.cyber.gc.ca/en/alerts-advisories/sonicwall-security-advisory-av26-1133">加拿大網路安全中心 AV26-1133</a>。</p><h2 id="4-GCP／Linux-Kernel：TCP-漏洞"><a href="#4-GCP／Linux-Kernel：TCP-漏洞" class="headerlink" title="4. GCP／Linux Kernel：TCP 漏洞"></a>4. GCP／Linux Kernel：TCP 漏洞</h2><p><strong>CVE-2026-98432｜GCP-2026-078｜11&#x2F;04</strong></p><p>Linux IPv4 TCP 堆疊漏洞可能造成核心當機或容器逃逸。Google 列出 GKE Standard、Autopilot 受影響；網路攻擊需要連得到相關 TCP listener，容器內亦有本地觸發途徑。Google 此公告的產品風險分級為 Medium，不等同原報告引用的通用 CVSS 分數。</p><p>盤點時須區分作業系統、Kernel flavor 與實際運行核心，不能把 generic 核心狀態套到 <code>linux-gcp</code>。本次未重建 11&#x2F;09 各發行版的歷史修補矩陣，請依官方現況核對，更新後確認新核心已生效。</p><p>來源：<a href="https://docs.cloud.google.com/support/bulletins#gcp-2026-078">Google Cloud GCP-2026-078</a>。</p><h2 id="5-Ubuntu：Java-憑證信任庫未同步"><a href="#5-Ubuntu：Java-憑證信任庫未同步" class="headerlink" title="5. Ubuntu：Java 憑證信任庫未同步"></a>5. Ubuntu：Java 憑證信任庫未同步</h2><p><strong>USN-9001-1｜11&#x2F;05</strong></p><p>系統 CA bundle 移除憑證後，Java JKS keystore 可能未同步移除，讓 Java 程式繼續信任已撤除的 CA。更新會修正同步行為並重新同步信任庫；公告沒有獨立 CVE。</p><table><thead><tr><th>Ubuntu</th><th><code>ca-certificates</code></th><th><code>ca-certificates-java</code></th></tr></thead><tbody><tr><td>22.04</td><td><code>20260816ubuntu0.22.04.2</code></td><td><code>20190909ubuntu1.4</code></td></tr><tr><td>24.04</td><td><code>20260816ubuntu0.24.04.2</code></td><td><code>20240118ubuntu0.24.04.1</code></td></tr><tr><td>26.04</td><td><code>20260816ubuntu0.26.04.2</code></td><td><code>20260311ubuntu0.26.04.1</code></td></tr><tr><td>26.10</td><td><code>20260816ubuntu0.26.10.2</code></td><td><code>20260311ubuntu0.26.10.1</code></td></tr></tbody></table><p>使用自訂 JKS、JDK 內建信任庫或容器映像時，須另外確認，不能只看 OS 套件更新。</p><p>來源：<a href="https://ubuntu.com/security/notices/USN-9001-1">Ubuntu USN-9001-1</a>。</p><h2 id="6-Google-Cloud-SDK：Python／Java-憑證更新"><a href="#6-Google-Cloud-SDK：Python／Java-憑證更新" class="headerlink" title="6. Google Cloud SDK：Python／Java 憑證更新"></a>6. Google Cloud SDK：Python／Java 憑證更新</h2><p><strong>GCP-2026-075｜11&#x2F;02</strong></p><p>eMudhra 憑證私鑰事件影響仍信任相關 CA 的應用程式。Google 表示其基礎設施未遭入侵，遙測未見相關工作負載利用證據。</p><p>公告要求檢查 <code>certifi</code>（至少 <code>2026.10.19</code>）、<code>httplib2</code>（<code>0.32.1</code>）、<code>grpcio</code>（<code>1.84.1</code> 或其他已修補分支），以及 Java <code>google-api-client</code>（<code>2.9.2</code>）。gRPC 使用的憑證集合不一定來自 OS，更新作業系統不代表應用程式已修好。完成依賴更新後重新建置、部署映像。</p><p>來源：<a href="https://docs.cloud.google.com/support/bulletins#gcp-2026-075">Google Cloud GCP-2026-075</a>。</p><h2 id="7-NGINX：舊版-Ubuntu-補上安全更新"><a href="#7-NGINX：舊版-Ubuntu-補上安全更新" class="headerlink" title="7. NGINX：舊版 Ubuntu 補上安全更新"></a>7. NGINX：舊版 Ubuntu 補上安全更新</h2><p><strong>USN-8955-2｜11&#x2F;05</strong></p><p>本次把先前 NGINX 修補擴及 Ubuntu 20.04、18.04、16.04、14.04，並修正 CVE-2026-42533。特定 regex、capture variable、<code>map</code> 或 <code>alias</code>／rewrite 組合可能造成當機或程式碼執行；僅看到 <code>alias</code> 不足以判定符合觸發條件。</p><p>Ubuntu 20.04 的公告修補版本為 <code>1.18.0-0ubuntu1.7+esm4</code>，其他舊版須對照各自套件表及 Pro／ESM 資格。Ubuntu 22.04 以上則查 USN-8955-1；Debian 必須另查其 Tracker，不能套用 Ubuntu 結論。本次未重新確認 Debian 12 的即時修補狀態。</p><p>來源：<a href="https://ubuntu.com/security/notices/USN-8955-2">Ubuntu USN-8955-2</a>。</p><h2 id="8-Chrome-157：瀏覽器安全更新"><a href="#8-Chrome-157：瀏覽器安全更新" class="headerlink" title="8. Chrome 157：瀏覽器安全更新"></a>8. Chrome 157：瀏覽器安全更新</h2><p><strong>11&#x2F;03 Stable 發布</strong></p><p>公告版本為 Linux <code>157.0.8103.38</code>，Windows／macOS <code>157.0.8103.38/.39</code>，包含記憶體安全等問題，且有 Critical 項目。應更新瀏覽器並重新啟動，確認新版本已實際載入。</p><p><strong>11&#x2F;13 校訂：</strong> 原週報寫 213 項修補，部分搜尋摘要仍如此顯示，但官方公告正文目前寫 <strong>212 項</strong>，本文以正文為準。原週報只舉低風險 CVE，不能代表整次更新的嚴重程度。本次未確認這批項目的野外利用狀態。</p><p>來源：<a href="https://chromereleases.googleblog.com/2026/11/stable-channel-update-for-desktop.html">Chrome Releases</a>。</p><h2 id="9-AWS-Serverless-MCP-Server：路徑穿越"><a href="#9-AWS-Serverless-MCP-Server：路徑穿越" class="headerlink" title="9. AWS Serverless MCP Server：路徑穿越"></a>9. AWS Serverless MCP Server：路徑穿越</h2><p><strong>CVE-2026-116635｜11&#x2F;02</strong></p><p>能影響 MCP agent 輸入的攻擊者，在特定條件下可讀取部署狀態目錄以外的 JSON；若啟用寫入，也可能建立或覆寫目錄外的 JSON。</p><p><code>awslabs.aws-serverless-mcp-server</code> 低於 <code>0.2.1</code> 受影響，<code>0.2.1</code> 已修補。AWS 未提供替代緩解措施，應更新套件，分叉版本也須帶入修正。公告未列 CVSS，本次未確認實際利用。</p><p>來源：<a href="https://aws.amazon.com/security/security-bulletins/2026-164-aws/">AWS 2026-164</a>。</p><h2 id="10-AWS-EKS：NetworkPolicy-隔離繞過"><a href="#10-AWS-EKS：NetworkPolicy-隔離繞過" class="headerlink" title="10. AWS EKS：NetworkPolicy 隔離繞過"></a>10. AWS EKS：NetworkPolicy 隔離繞過</h2><p><strong>CVE-2026-122266｜11&#x2F;04</strong></p><p>共享 eBPF 連線狀態隔離不足，可能讓具相鄰環境存取能力的已驗證使用者繞過同節點其他 Pod 的 ingress NetworkPolicy。</p><table><thead><tr><th>元件</th><th>受影響版本</th><th>修補版本</th></tr></thead><tbody><tr><td><code>aws-network-policy-agent</code></td><td><code>&lt; 1.3.7</code></td><td><code>1.3.7</code></td></tr><tr><td>Amazon VPC CNI Managed Add-on</td><td><code>&lt; 1.22.3</code></td><td><code>1.22.3</code></td></tr></tbody></table><p>AWS 表示沒有替代緩解措施。使用 EKS NetworkPolicy 時應確認元件版本及更新後的網路隔離行為。公告未列 CVSS，本次未確認實際利用。</p><p>來源：<a href="https://aws.amazon.com/security/security-bulletins/2026-170-aws/">AWS 2026-170</a>。</p><h2 id="11-AWS-Babelfish：TDS-記憶體安全漏洞"><a href="#11-AWS-Babelfish：TDS-記憶體安全漏洞" class="headerlink" title="11. AWS Babelfish：TDS 記憶體安全漏洞"></a>11. AWS Babelfish：TDS 記憶體安全漏洞</h2><p><strong>CVE-2026-119923、CVE-2026-119924｜11&#x2F;06</strong></p><p>前者涉及 TDS 握手，可由未驗證遠端攻擊者影響資料庫程序；後者涉及 TDS RPC，已驗證攻擊者可能讀取鄰近記憶體或造成服務中斷。</p><p>Babelfish for PostgreSQL extension 的修補版包含 <code>4.10</code>、<code>5.6</code>、<code>6.1</code>。Aurora 的修補門檻依分支不同，應對照公告中的 Aurora／Babelfish 版本配對，並完成待處理維護，不能直接套用 extension 版號。更新前可先把 TDS 連接埠來源限制為可信來源。本次未確認實際利用。</p><p>來源：<a href="https://aws.amazon.com/security/security-bulletins/2026-166-aws/">AWS 2026-166</a>。</p><h2 id="12-Python：Pillow、Twisted、Tornado"><a href="#12-Python：Pillow、Twisted、Tornado" class="headerlink" title="12. Python：Pillow、Twisted、Tornado"></a>12. Python：Pillow、Twisted、Tornado</h2><p>三項更新的適用情境不同，不應只用「Python 有漏洞」概括。</p><table><thead><tr><th>元件／公告</th><th>影響與處理</th></tr></thead><tbody><tr><td>Pillow／USN-8999-1，11&#x2F;04</td><td>影像、字型與 filter 處理可造成資訊外洩、資源耗盡，部分問題可能執行程式碼；處理不可信影像的服務應檢查依賴。</td></tr><tr><td>Twisted／USN-9000-1，11&#x2F;04</td><td>CVE-2026-106454 涉及 IMAP mailbox list wildcard；已驗證使用者可造成資源耗盡。Ubuntu 22.04 對應 <code>22.1.0-2ubuntu2.8</code>。</td></tr><tr><td>Tornado／USN-8952-2，11&#x2F;06</td><td>CVE-2026-103263 的先前修補不完整，造成繼承 <code>StaticFileHandler</code> 的應用（如 Jupyter）靜態檔案服務回歸，本次予以修正。</td></tr></tbody></table><p>APT 安裝的 Python 套件與 <code>pip</code>、Poetry、<code>uv</code> 的虛擬環境要分開盤點。更新後除了版本檢查，也應測試影像處理、郵件及靜態檔案功能。</p><p>來源：<a href="https://ubuntu.com/security/notices/USN-8999-1">Pillow</a>、<a href="https://ubuntu.com/security/notices/USN-9000-1">Twisted</a>、<a href="https://ubuntu.com/security/notices/USN-8952-2">Tornado</a>。</p><h2 id="13-Debian：APT、zlib-與-Kernel-公告"><a href="#13-Debian：APT、zlib-與-Kernel-公告" class="headerlink" title="13. Debian：APT、zlib 與 Kernel 公告"></a>13. Debian：APT、zlib 與 Kernel 公告</h2><table><thead><tr><th>日期／公告</th><th>套件</th><th>重點</th></tr></thead><tbody><tr><td>11&#x2F;04 DSA-6607-1</td><td>APT</td><td>CVE-2026-109518；Trixie 修補版 <code>3.0.4</code>，詳細條件見第 1 節。</td></tr><tr><td>11&#x2F;07 DSA-6613-1</td><td>zlib</td><td>特製輸入可能造成 DoS 或程式碼執行；Trixie 修補版 <code>1:1.3.dfsg+really1.3.1-1+deb13u1</code>。</td></tr><tr><td>11&#x2F;08 DSA-6616-1</td><td>Linux</td><td>權限提升、DoS、資訊外洩等問題；Trixie 修補版 <code>6.12.116-1</code>。</td></tr></tbody></table><p>上述 DSA 的版本表主要針對 Debian 13（Trixie）。Debian 12（Bookworm）應另看 Tracker／LTS 公告，不能因為 DSA 已發布就認定同樣修好。</p><p>來源：<a href="https://lists.debian.org/debian-security-announce/2026/msg00526.html">APT 公告</a>、<a href="https://lists.debian.org/debian-security-announce/2026/msg00532.html">zlib 公告</a>、<a href="https://lists.debian.org/debian-security-announce/2026/msg00536.html">Linux 公告</a>。</p><h2 id="14-PostgreSQL-14：支援期限到期"><a href="#14-PostgreSQL-14：支援期限到期" class="headerlink" title="14. PostgreSQL 14：支援期限到期"></a>14. PostgreSQL 14：支援期限到期</h2><p>這不是新漏洞，而是版本維護期限。官方版本政策列出的 PostgreSQL 14 最終發行日為 <strong>2026&#x2F;11&#x2F;12</strong>。</p><p><strong>11&#x2F;13 更新：</strong> 官方目前列出 <code>14.25</code>，因此原報告「最後版本為 14.24」的說法不再適用。盤點仍使用 14 的資料庫，確認升級或額外維護方案；最後一次小版本更新不能取代後續主版本遷移。大版本升級需先測試資料遷移、擴充套件與回復流程。</p><p>來源：<a href="https://www.postgresql.org/support/versioning/">PostgreSQL 版本政策</a>。</p><h2 id="其他平台追蹤"><a href="#其他平台追蹤" class="headerlink" title="其他平台追蹤"></a>其他平台追蹤</h2><p>以下保留 11&#x2F;09 原報告的追蹤範圍。原檢索未取得足夠證據列出該週新增重大事件；這不是「沒有漏洞」的保證，11&#x2F;13 的補稿也沒有重跑所有平台的完整歷史調查。</p><table><thead><tr><th>平台</th><th>本期紀錄與後續關注</th></tr></thead><tbody><tr><td>GitHub／Actions</td><td>未確認新的重大平台事件；持續盤點第三方 Action、依賴及 token 權限。</td></tr><tr><td>Docker Engine／Desktop</td><td>未確認該週新增重大公告；原報告提及既有憑證紀錄風險，但本次未核實其具體公告，不將它列為已確認新事件。</td></tr><tr><td>Windows／Microsoft 365</td><td>原報告未確認另需列為緊急處理的新事件。</td></tr><tr><td>Azure</td><td>原報告未確認需客戶立即處理的新重大公告。</td></tr><tr><td>Figma</td><td>未確認可由官方來源支持的該週重大事件。</td></tr><tr><td>OpenAI／ChatGPT／API</td><td>未確認可由官方來源支持的該週重大事件。</td></tr><tr><td>Anthropic／Claude／API</td><td>未確認可由官方來源支持的該週重大事件。</td></tr><tr><td>Gemini／Gemini API</td><td>未確認可由官方來源支持的該週重大事件。</td></tr></tbody></table><h2 id="檢查順序"><a href="#檢查順序" class="headerlink" title="檢查順序"></a>檢查順序</h2><ol><li>確認是否使用 WordPress、SonicWall，優先處理已知遭利用項目。</li><li>檢查 APT、NGINX、Kernel 的完整套件版本與適用設定。</li><li>分別檢查 OS、Java、Python 與容器的憑證信任庫及依賴。</li><li>盤點 EKS、MCP Server、Babelfish，套用對應分支的更新。</li><li>更新瀏覽器，處理 PostgreSQL 14 的版本遷移。</li></ol><p>以下只讀取本機狀態，不會安裝更新：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">apt-cache policy apt nginx ca-certificates ca-certificates-java</span><br><span class="line">apt-config dump | grep -i <span class="string">&#x27;Acquire::Retries&#x27;</span></span><br><span class="line"><span class="built_in">uname</span> -r</span><br></pre></td></tr></table></figure><p>套件版本、執行中的版本及設定條件都要符合，才可判定修補生效。本文未檢查任何個別主機，也未保留私人環境設定。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;整理 2026&amp;#x2F;11&amp;#x2F;02–11&amp;#x2F;08 的 14 個資安主題與其他平台追蹤結果。11&amp;#x2F;13 重新核對官方來源，修正 Chrome 修補數量，補上 PostgreSQL 14 的最新版本資訊。&lt;/p&gt;
&lt;p&gt;優先確認 APT 修補；使用 WordPress 或 SonicWall 的環境，應先處理已知遭利用的漏洞。以下是通用盤點建議，不代表任何個別系統已受影響或已完成修補。&lt;/p&gt;</summary>
    
    
    
    <category term="資安週報" scheme="https://andyhung0723.github.io/categories/%E8%B3%87%E5%AE%89%E9%80%B1%E5%A0%B1/"/>
    
    
    <category term="Ubuntu" scheme="https://andyhung0723.github.io/tags/Ubuntu/"/>
    
    <category term="Linux" scheme="https://andyhung0723.github.io/tags/Linux/"/>
    
    <category term="雲端安全" scheme="https://andyhung0723.github.io/tags/%E9%9B%B2%E7%AB%AF%E5%AE%89%E5%85%A8/"/>
    
    <category term="開發工具" scheme="https://andyhung0723.github.io/tags/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>GA4 vs GA3 來源/媒介 BigQuery 欄位解析</title>
    <link href="https://andyhung0723.github.io/2023/04/20/ga/ga4_share_0420/"/>
    <id>https://andyhung0723.github.io/2023/04/20/ga/ga4_share_0420/</id>
    <published>2023-04-20T08:30:00.000Z</published>
    <updated>2026-11-13T13:54:49.998Z</updated>
    
    <content type="html"><![CDATA[<p>👉 文章內容深度 : 3&#x2F;5顆星<br>👉 適用對象 : 有使用 BigQuery 製作來源&#x2F;媒介報表</p><span id="more"></span><h3 id="▶-什麼是來源-媒介"><a href="#▶-什麼是來源-媒介" class="headerlink" title="▶ 什麼是來源&#x2F;媒介 ?"></a>▶ <strong>什麼是來源&#x2F;媒介 ?</strong></h3><p>  簡單來說就是判斷這個流量從哪邊來? 是從 Google 搜尋引擎進入網站還是從 FB 粉專進入網站。<br>以下為 GA3 &amp; GA4 的來源&#x2F;媒介報表路徑</p><ul><li>GA3 : 獲客 &gt; 所有流量 &gt; 來源&#x2F;媒介</li><li>GA4 : 獲客 &gt; 流量開發 : 工作階段預設管道分組 (如下圖)<br><img src="https://i.imgur.com/hVTllIw.png"></li></ul><h3 id="▶-GA3-vs-GA4-BigQuery-來源-媒介欄位比較表"><a href="#▶-GA3-vs-GA4-BigQuery-來源-媒介欄位比較表" class="headerlink" title="▶ GA3 vs. GA4 BigQuery 來源&#x2F;媒介欄位比較表"></a>▶ <strong>GA3 vs. GA4 BigQuery 來源&#x2F;媒介欄位比較表</strong></h3><p>GA3 時代，從 BigQuery 中提取來源&#x2F;媒介數據時，會使用欄位「trafficSource.source」&amp;「trafficSource.medium」，這是沒有錯的!這兩個欄位代表的是每次進站的渠道。<br>&lt;<a href="https://support.google.com/analytics/answer/3437719?hl=zh-Hant">附上 GA3 匯出 BigQuery 的結構定義</a>&gt;</p><p>當看到 GA4 匯出到 BigQuery 的 Dataset 中看到「traffic_source.source」&amp;「traffic_source.medium」時，心中是不是無比喜悅，就是他惹 :100: </p><p><strong>但是!</strong> 現在我們來看一下 Google 的官方文件說明(附上截圖&amp;<a href="https://support.google.com/analytics/answer/7029846?hl=zh-Hant&ref_topic=9359001&sjid=6130283979471431016-AP#zippy=%2Ctraffic-source">文件</a>)，<br><span style="color:grab">補充:這兩個欄位會對應到 GA4 維度為「最初招攬到使用者的來源&#x2F;媒介」</span></p><ul><li>traffic_source.source: <span style="color:red">初次招攬</span>到使用者的聯播網名稱。</li><li>traffic_source.medium: <span style="color:red">初次招攬</span>到使用者的媒介名稱。</li></ul><p><img src="https://i.imgur.com/6Ukf3Ai.png"></p><p>「初次招攬」指的是第一次進到網站的使用者是從哪個渠道進入網站，是 FB 廣告還是 Google 自然搜尋等等。<br>舉例來說 :<br>小明點了 Google 廣告，<strong>第一次</strong>進到網站中，那欄位值會如下</p><ul><li>traffic_source.source: google</li><li>traffic_source.medium: cpc</li></ul><p>那小明隔天從 LINE 官方帳號進入網站，那欄位值是什麼?<br><span style="color:blue"><em>值還是一樣的 ! 因為「traffic_source.source 和 traffic_source.medium 這兩個欄位就是這兩個欄位僅記錄用戶首次訪問網站時的來源媒介</em></span></p><ul><li>traffic_source.source: google</li><li>traffic_source.medium: cpc</li></ul><h3 id="▶那第2次的來源媒介要怎麼取得"><a href="#▶那第2次的來源媒介要怎麼取得" class="headerlink" title="▶那第2次的來源媒介要怎麼取得?"></a>▶<strong>那第2次的來源媒介要怎麼取得?</strong></h3><p>GA4 的數據模型是由事件組成，所以每個 event_name 對應一個資料列。<br>event_name &#x3D; page_view 指的就是每一次的網站瀏覽，所以第二次進站的來源媒介，會出現在事件名為 page_view 的資料列中，包含 source 和 medium 參數。</p><h3 id="▶2種情境與對應值，分享給大家"><a href="#▶2種情境與對應值，分享給大家" class="headerlink" title="▶2種情境與對應值，分享給大家"></a>▶<strong>2種情境與對應值，分享給大家</strong></h3><h4 id="情境1-小明從-Google-自然搜尋第1次進站到首頁，點了站內-UTM-Urchin-Tracking-Module-到活動頁"><a href="#情境1-小明從-Google-自然搜尋第1次進站到首頁，點了站內-UTM-Urchin-Tracking-Module-到活動頁" class="headerlink" title="情境1 :小明從 Google 自然搜尋第1次進站到首頁，點了站內 UTM(Urchin Tracking Module) 到活動頁"></a>情境1 :小明從 Google 自然搜尋第1次進站到首頁，點了站內 UTM(Urchin Tracking Module) 到活動頁</h4><!--![](https://i.imgur.com/EVFY6f9.png)--><p>下表為 BQ 中的資料列示意</p><table><thead><tr><th>event_date</th><th>event_name</th><th>event_params.key</th><th>event_params_value.string_value</th><th>traffic_source.source</th><th>traffic_source.medium</th></tr></thead><tbody><tr><td>20230222</td><td>first_visit</td><td>page_location</td><td>首頁網址</td><td>google</td><td>organic</td></tr><tr><td>20230222</td><td>session_start</td><td>page_location</td><td>首頁網址</td><td>google</td><td>organic</td></tr><tr><td>20230222</td><td>page_view</td><td>page_location</td><td>首頁網址</td><td>google</td><td>organic</td></tr><tr><td></td><td></td><td>source</td><td>google</td><td></td><td></td></tr><tr><td></td><td></td><td>medium</td><td>organic</td><td></td><td></td></tr><tr><td>20230222</td><td>page_view</td><td>page_location</td><td>站內UTM活動頁</td><td>google</td><td>organic</td></tr><tr><td></td><td></td><td>source</td><td>Amy1</td><td></td><td></td></tr><tr><td></td><td></td><td>medium</td><td>Test1</td><td></td><td></td></tr></tbody></table><h4 id="情境2-延續情境1，隔天小明點了-FB-粉專的貼文進入了網站商品頁，粉專貼文的連結有帶-UTM-為-Facebook-post"><a href="#情境2-延續情境1，隔天小明點了-FB-粉專的貼文進入了網站商品頁，粉專貼文的連結有帶-UTM-為-Facebook-post" class="headerlink" title="情境2 : 延續情境1，隔天小明點了 FB 粉專的貼文進入了網站商品頁，粉專貼文的連結有帶 UTM 為 Facebook &#x2F; post"></a>情境2 : 延續情境1，隔天小明點了 FB 粉專的貼文進入了網站商品頁，粉專貼文的連結有帶 UTM 為 Facebook &#x2F; post</h4><p>下表為 BQ 中的資料列示意</p><!--![](https://i.imgur.com/djMJipF.png)--><table><thead><tr><th>event_date</th><th>event_name</th><th>event_params.key</th><th>event_params_value.string_value</th><th>traffic_source.source</th><th>traffic_source.medium</th></tr></thead><tbody><tr><td>20230223</td><td>session_start</td><td>page_location</td><td>商品頁</td><td>google</td><td>organic</td></tr><tr><td>20230223</td><td>page_view</td><td>page_location</td><td>商品頁</td><td>google</td><td>organic</td></tr><tr><td></td><td></td><td>source</td><td>Facebook</td><td></td><td></td></tr><tr><td></td><td></td><td>medium</td><td>post</td><td></td><td></td></tr></tbody></table><h4 id="結論-traffic-source-欄位僅記錄用戶首次訪問網站時的來源媒介，不會因未來用戶進入網站的渠道而改變其值。"><a href="#結論-traffic-source-欄位僅記錄用戶首次訪問網站時的來源媒介，不會因未來用戶進入網站的渠道而改變其值。" class="headerlink" title="結論 : traffic_source 欄位僅記錄用戶首次訪問網站時的來源媒介，不會因未來用戶進入網站的渠道而改變其值。"></a><span style="color:blue">結論 : traffic_source 欄位僅記錄用戶首次訪問網站時的來源媒介，不會因未來用戶進入網站的渠道而改變其值。</span></h4><p>附上查詢 SQL </p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> event_date,event_name, event_params, traffic_source.source, traffic_source.medium</span><br><span class="line"><span class="keyword">FROM</span> `你的工作表名稱`</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;👉 文章內容深度 : 3&amp;#x2F;5顆星&lt;br&gt;👉 適用對象 : 有使用 BigQuery 製作來源&amp;#x2F;媒介報表&lt;/p&gt;</summary>
    
    
    
    <category term="Google Analytics" scheme="https://andyhung0723.github.io/categories/Google-Analytics/"/>
    
    
  </entry>
  
  <entry>
    <title>Google 官方正式宣布「項目範圍的自訂維度 (item scope)」上線啦!</title>
    <link href="https://andyhung0723.github.io/2023/04/16/ga/ga4_share_0416/"/>
    <id>https://andyhung0723.github.io/2023/04/16/ga/ga4_share_0416/</id>
    <published>2023-04-16T04:30:00.000Z</published>
    <updated>2026-11-13T13:54:49.394Z</updated>
    
    <content type="html"><![CDATA[<p>👉 文章內容深度 : 3&#x2F;5顆星<br>👉 適用對象 : GA4 有做電子商務事件</p><span id="more"></span><p>▶ <strong>什麼是項目範圍自訂維度(item scope) ?</strong><br>項目範圍的維度，是指專門用來追蹤 GA4 電子商務事件中商品的資訊，例如 : 商品名稱、商品id、顏色、尺寸、重量等等。<br>在項目範圍的維度中，有分 GA4 預設維度 &amp; 最近才公布的自訂維度。<br>舉例來說 :<br>GA4 預設維度 : 商品名稱(item_name)、商品編號(item_id)、商品價格(price)等等。<a href="https://support.google.com/analytics/answer/12947610?hl=zh-Hant&ref=tako-analytics">官方文件</a><br>自訂維度 : 用來補足 GA4 預設維度中沒有的維度，由自己定義，例如 : 課程長度、售票種類、商品關鍵字等等。<br>數量限制 : 免費版資源 : 10個 &#x2F; 付費版資源 : 25個</p><p>▶ <strong>項目範圍自訂維度(item scope)情境舉例</strong><br>以這一個商品舉例，右邊 items 陣列中的參數(item_name、item_id、price 等)都屬於 GA4 的預設項目範圍維度。<br><img src="https://i.imgur.com/GqUrcxP.png"></p><p>若想多追蹤杯子的容量，GA4 預設的項目範圍維度又沒有提供對應參數，這時候，就可以自訂一個項目範圍的自訂維度，Datalayer 調整後如下圖，新增的參數一定要放在 items 陣列中。<br><img src="https://i.imgur.com/rk38GYv.png"></p><p>▶ <strong>項目範圍自訂維度(item scope)要如何在 GA4 中設定 ?</strong><br>確認有把自訂的參數送到 GA4 後，接下來就是要在 GA4 中設定自訂維度，<br>設定路徑 : 管理(左下角齒輪) &gt; 自訂定義 &gt; 建立自訂維度(藍底按鈕) &gt; 範圍選 : 項目 &gt; 按下儲存<br>可參考以下圖片，依序設定。<br><img src="https://i.imgur.com/87tr979.png"></p><p>(下圖)記得範圍要選「項目」，項目參數需要填寫您在網站中傳送的參數名稱，以本次範例為例，則是填入 capacity (並非照填寫 capacity) 。<br><img src="https://i.imgur.com/rbWXou3.png"></p><p>(下圖)儲存後，會出現範圍為「項目」的自訂維度。<br><img src="https://i.imgur.com/U29tNgA.png"></p><p>▶ 項目範圍自訂維度(item scope)在 GA4 探索報表中的呈現<br>目前還無法在預設報表中，透過次要維度或是利用自訂報表功能拉取項目範圍維度，所以設定完的項目範圍自訂維度無法呈現在電子商務報表中，只能在探索報表使用，這部分較可惜，希望未來能更新上去。</p><ul><li>補充提醒，電子商務相關的維度都只能搭配使用部分指標，所以建議先拉取項目範圍的維度後，再選擇指標(無法使用的指標會被反灰)。</li></ul><p><img src="https://i.imgur.com/j24EcAj.png"></p><p>此外Looker Studio 中也無法拉取項目範圍的自訂維度，以上的限制待未來更新後，再分享給大家~</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;👉 文章內容深度 : 3&amp;#x2F;5顆星&lt;br&gt;👉 適用對象 : GA4 有做電子商務事件&lt;/p&gt;</summary>
    
    
    
    <category term="Google Analytics" scheme="https://andyhung0723.github.io/categories/Google-Analytics/"/>
    
    
  </entry>
  
  <entry>
    <title>position:sticky 遇到 overflow 時失效解法</title>
    <link href="https://andyhung0723.github.io/2022/06/08/position-sticky-issue/"/>
    <id>https://andyhung0723.github.io/2022/06/08/position-sticky-issue/</id>
    <published>2022-06-08T14:21:14.000Z</published>
    <updated>2026-11-13T13:54:50.645Z</updated>
    
    <content type="html"><![CDATA[<p>今天在處理將 table 表頭凍結在最上方時，找到了使用<code>position: sticky</code>的方式解決，但若我要同時在小畫面時讓這個 table 的 X 軸能夠有 scroll bar 卻出現了問題，以下紀錄一下問題原因與解決方式。</p><span id="more"></span><blockquote><p>範例連結：<a href="https://codepen.io/andyhung0723/pen/YzeOovW">https://codepen.io/andyhung0723/pen/YzeOovW</a></p></blockquote><h2 id="問題"><a href="#問題" class="headerlink" title="問題"></a>問題</h2><p>假設我有一個 table，若我想將它的表頭凍結在最上方不動，可以使用<code>position: sticky</code>：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.table-sticky</span> <span class="selector-class">.th</span> &#123;</span><br><span class="line">  <span class="attribute">position</span>: sticky;</span><br><span class="line">  <span class="attribute">top</span>: <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>若在小畫面時想要此 table 不要撐開整體寬度，一般會在外層使用<code>overflow-x: auto</code>來讓 X 軸產生 scroll bar：</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.table-sticky-container</span> &#123;</span><br><span class="line">  <span class="attribute">overflow-x</span>: auto;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>此時就會發現<strong>原本<code>position: sticky</code>的凍結效果卻失效了</strong>。</p><br><h2 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h2><p>經測試發現只要<code>position: sticky</code>上所有階層的父元素只要有一個的<code>overflow</code>值是<code>visible</code>以外的其他值，就會導致失效。</p><br><h2 id="解法"><a href="#解法" class="headerlink" title="解法"></a>解法</h2><p>目前單純使用 CSS 貌似沒有解法，因此我使用 JavaScript 的 scroll 事件來動態 transform 表頭的位置來解決，程式碼如下：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="title function_">addEventListener</span>(<span class="string">&#x27;scroll&#x27;</span>, <span class="keyword">function</span>(<span class="params">event</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> scrollTop = <span class="variable language_">window</span>.<span class="property">pageYOffset</span> || <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="property">scrollTop</span> || <span class="variable language_">document</span>.<span class="property">body</span>.<span class="property">scrollTop</span> || <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">var</span> stickyTables = <span class="variable language_">document</span>.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;.table-sticky&#x27;</span>);</span><br><span class="line">  <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span> ; i &lt; stickyTables.<span class="property">length</span> ; i++) &#123;</span><br><span class="line">    <span class="keyword">var</span> thead = stickyTables[i].<span class="title function_">querySelector</span>(<span class="string">&#x27;thead&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> offsetTop = stickyTables[i].<span class="property">offsetTop</span>;</span><br><span class="line">    <span class="keyword">var</span> offsetHeight = stickyTables[i].<span class="property">offsetHeight</span> - thead.<span class="property">offsetHeight</span>;</span><br><span class="line">    <span class="keyword">var</span> transformY = <span class="title function_">getTranslateY</span>(thead);</span><br><span class="line">    <span class="keyword">if</span>(scrollTop &gt;= offsetTop &amp;&amp; scrollTop &lt;= offsetTop + offsetHeight) &#123;</span><br><span class="line">      transformY = scrollTop - offsetTop;</span><br><span class="line">    &#125;<span class="keyword">else</span> <span class="keyword">if</span>(scrollTop &lt; offsetTop)&#123;</span><br><span class="line">      transformY = <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    thead.<span class="property">style</span>.<span class="property">transform</span> = <span class="string">&#x27;translateY(&#x27;</span>+ transformY +<span class="string">&#x27;px)&#x27;</span>;</span><br><span class="line">  &#125; </span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getTranslateY</span>(<span class="params">element</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> style = <span class="variable language_">window</span>.<span class="title function_">getComputedStyle</span>(element);</span><br><span class="line">  <span class="keyword">var</span> matrix = <span class="keyword">new</span> <span class="title class_">WebKitCSSMatrix</span>(style.<span class="property">transform</span>);</span><br><span class="line">  <span class="keyword">return</span> matrix.<span class="property">m42</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;今天在處理將 table 表頭凍結在最上方時，找到了使用&lt;code&gt;position: sticky&lt;/code&gt;的方式解決，但若我要同時在小畫面時讓這個 table 的 X 軸能夠有 scroll bar 卻出現了問題，以下紀錄一下問題原因與解決方式。&lt;/p&gt;</summary>
    
    
    
    <category term="CSS" scheme="https://andyhung0723.github.io/categories/CSS/"/>
    
    
  </entry>
  
  <entry>
    <title>Angular 取得元素 offsetWidth 時有誤解法</title>
    <link href="https://andyhung0723.github.io/2022/06/01/angular-offsetwidth-bug/"/>
    <id>https://andyhung0723.github.io/2022/06/01/angular-offsetwidth-bug/</id>
    <published>2022-06-01T15:18:58.000Z</published>
    <updated>2026-11-13T13:54:48.788Z</updated>
    
    <content type="html"><![CDATA[<p>今天在工作上遇到一個問題，我有一個功能執行時會切換兩個 Angular Component 的顯示，當切換到其中一個 Component 時，我會去抓取當下它的 offsetWidth 做運算使用，但抓這個 offsetWidth 卻憑空少了<code>15px</code>，後來在找了一段時間終於找到原因，在這邊以一個簡化過的例子紀錄一下。</p><span id="more"></span><blockquote><p>範例連結：<a href="https://stackblitz.com/edit/angular-ivy-bmpsfk">https://stackblitz.com/edit/angular-ivy-bmpsfk</a></p></blockquote><h2 id="問題"><a href="#問題" class="headerlink" title="問題"></a>問題</h2><p>假設有一個按鈕，點擊之後可依狀態顯示不同的 Component。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">app-first</span> *<span class="attr">ngIf</span>=<span class="string">&quot;visibleComponent === &#x27;first&#x27;; else second&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">app-first</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">ng-template</span> #<span class="attr">second</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">app-second</span>&gt;</span><span class="tag">&lt;/<span class="name">app-second</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">ng-template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span> (<span class="attr">click</span>)=<span class="string">&quot;switch()&quot;</span>&gt;</span>switch<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://i.imgur.com/1wC0QPT.png" alt="first component layout"></p><p><img src="https://i.imgur.com/FIp0NkZ.png" alt="second component layout"></p><br><p>在 first component 中我們嘗試取得該元素的<code>offsetWidth</code>。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> #<span class="attr">content</span>&gt;</span>first component<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="title function_">ngAfterViewInit</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;content width: &#x27;</span>, <span class="variable language_">this</span>.<span class="property">content</span>.<span class="property">nativeElement</span>.<span class="property">offsetWidth</span>);</span><br><span class="line">&#125;</span><br><span class="line">...</span><br></pre></td></tr></table></figure><br><p>結果在當由 second 切換到 first 時，取得的 offsetWidth 為<code>624px</code>，但實際應為<code>639px</code>，少了<code>15px</code>。</p><p><img src="https://i.imgur.com/aXiPGrV.png" alt="result01"></p><br><h2 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h2><p>經過測試後發現當有載入<code>BrowserAnimationsModule</code>才會發生此問題，且是 second component 中有 scroll bar 的原因，導致在取得 offsetWidth 時少了 15px。</p><p><img src="https://i.imgur.com/FIp0NkZ.png" alt="second component layout"></p><p>但明明我是在 first component 中取 offsetWidth 阿？怎麼會吃到 scroll bar？</p><p>原來是在 ngAfterViewInit 執行的當下子 Component 的畫面會比父 Component 還早運算，我們 ngIf 的條件是寫在父 Component 進行判斷，所以當下吃到的父層寬度還會保留在切換到另一個 Component 之前。</p><blockquote><p>子 Component 的 ngAfterViewInit 也會比父 Component 的同一個事件還早執行。</p></blockquote><p>由於 second component 多了 scroll bar，且在載入<code>BrowserAnimationsModule</code>時 scroll bar 會被算成 15px 的空間，所以在取得 offsetWidth 會少了 scroll bar 佔去的寬度。</p><br><h2 id="解法"><a href="#解法" class="headerlink" title="解法"></a>解法</h2><p>由於是執行順序的問題，所以最簡單的解法就是透過<code>setTimeout</code>將取得 offsetWidth 的動作強制移動置 event loop 的最後執行。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="title function_">ngAfterViewInit</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;content width: &#x27;</span>, <span class="variable language_">this</span>.<span class="property">content</span>.<span class="property">nativeElement</span>.<span class="property">offsetWidth</span>);</span><br><span class="line"></span><br><span class="line">  <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(</span><br><span class="line">      <span class="string">&#x27;content width after: &#x27;</span>,</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">content</span>.<span class="property">nativeElement</span>.<span class="property">offsetWidth</span></span><br><span class="line">    );</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><br><p>執行結果<br><img src="https://i.imgur.com/w0wPgDe.png" alt="result02"></p><p>目前只有嘗試到這個方式，若有找到更好的寫法會再更新。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;今天在工作上遇到一個問題，我有一個功能執行時會切換兩個 Angular Component 的顯示，當切換到其中一個 Component 時，我會去抓取當下它的 offsetWidth 做運算使用，但抓這個 offsetWidth 卻憑空少了&lt;code&gt;15px&lt;/code&gt;，後來在找了一段時間終於找到原因，在這邊以一個簡化過的例子紀錄一下。&lt;/p&gt;</summary>
    
    
    
    <category term="Angular" scheme="https://andyhung0723.github.io/categories/Angular/"/>
    
    
  </entry>
  
  <entry>
    <title>Angular Lazy Loading</title>
    <link href="https://andyhung0723.github.io/2022/05/29/angular-lazy-loading/"/>
    <id>https://andyhung0723.github.io/2022/05/29/angular-lazy-loading/</id>
    <published>2022-05-29T07:07:01.000Z</published>
    <updated>2026-11-13T13:54:47.560Z</updated>
    
    <content type="html"><![CDATA[<p>在 Angular 應用程式一載入時，預設會將所有的 Module 一次全部載入，但如果今天應用程式規模很大，或是某些 Module 中需要載入的東西過多，就會拖到整個應用程式的載入時間。</p><p>為了解決這個問題，Angular 有針對 Module 提供 Lazy Loading 的功能，簡單來說就是當需要此 Module 的時候再進行載入，如此就不會影響到整個應用程式的效能。</p><span id="more"></span><h2 id="實現方式"><a href="#實現方式" class="headerlink" title="實現方式"></a>實現方式</h2><p>透過 Angular Router 中內建的功能即可實現，步驟如下：</p><ol><li>修改<code>app-routing.module.ts</code></li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="attr">routes</span>: <span class="title class_">Routes</span> = [</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;customers&#x27;</span>,</span><br><span class="line">    <span class="attr">loadChildren</span>: <span class="function">() =&gt;</span> <span class="keyword">import</span>(<span class="string">&#x27;./customers/customers.module&#x27;</span>).<span class="title function_">then</span>(<span class="function"><span class="params">m</span> =&gt;</span> m.<span class="property">CustomersModule</span>)</span><br><span class="line">  &#125;</span><br><span class="line">];</span><br></pre></td></tr></table></figure><p>利用<code>loadChildren</code>這個屬性，我們就可以透過 import 將我們想要 lazy loading 的 Module，在應用程式觸發到<code>path</code>中定義的路由(在這個例子中就是<code>/customers</code>)的時候將 CustomersModule 進行載入。</p><ol start="2"><li>修改<code>customers.module.ts</code></li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">CustomersRoutingModule</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;./customers-routing.module&#x27;</span>;</span><br><span class="line"></span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">  <span class="attr">declarations</span>: [</span><br><span class="line">    <span class="title class_">CustomersComponent</span></span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">imports</span>: [</span><br><span class="line">    <span class="title class_">CommonModule</span>,</span><br><span class="line">    <span class="title class_">CustomersRoutingModule</span></span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>額外新增<code>customers-routing.module.ts</code>，並新增到 CustomersModule 的 imports 中，我們會將關於此 Module 下 Router 的設定拆出來放在這個檔案中。</p><ol start="3"><li>新增<code>customers-routing.module.ts</code></li></ol><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="attr">routes</span>: <span class="title class_">Routes</span> = [</span><br><span class="line">  &#123; </span><br><span class="line">    <span class="attr">path</span>: <span class="string">&#x27;info&#x27;</span>, </span><br><span class="line">    <span class="attr">component</span>: <span class="title class_">CustomersComponent</span> </span><br><span class="line">  &#125;</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">  <span class="attr">imports</span>: [<span class="title class_">RouterModule</span>.<span class="title function_">forChild</span>(routes)],</span><br><span class="line">  <span class="attr">exports</span>: [<span class="title class_">RouterModule</span>]</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">CustomersRoutingModule</span> &#123; &#125;</span><br></pre></td></tr></table></figure><p>這邊我們就可以定義在子路徑下要載入哪個 Component，最終的路徑會是原本<code>app-routing.module.ts</code>中定義的<code>path</code>加上這邊定義的<code>path</code>，以上例來說就會是在<code>/customers/info</code>下讀取到 CustomersComponent。這邊要注意需要用<code>forChild</code>來定義子路由。</p><h2 id="透過指令建立"><a href="#透過指令建立" class="headerlink" title="透過指令建立"></a>透過指令建立</h2><p>如果我們在一開始就決定要使用 lazy loading 的方式載入 Module，也可以選擇用以下指令直接建立好上述的元件：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ng generate module customers --route customers --module app.module</span><br></pre></td></tr></table></figure><h2 id="實驗"><a href="#實驗" class="headerlink" title="實驗"></a>實驗</h2><p>我們可以在<code>customers.components.ts</code>中加上<code>console.log</code>來實驗是否有 lazy loading</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">CustomersComponent</span> implements <span class="title class_">OnInit</span> &#123;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line"></span><br><span class="line">  <span class="title function_">ngOnInit</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Customers Component Init&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li><p>讀取 <a href="http://localhost:4200/">http://localhost:4200</a><br><img src="https://i.imgur.com/pE6DTB9.png" alt="localhost:4200"></p></li><li><p>讀取 <a href="http://localhost:4200/customers">http://localhost:4200/customers</a><br><img src="https://i.imgur.com/ncZUBab.png" alt="localhost:4200&#x2F;customers"></p></li></ul><h2 id="注意事項"><a href="#注意事項" class="headerlink" title="注意事項"></a>注意事項</h2><ul><li>如果 Module 需要 lazy loading，需注意<code>app.module.ts</code>裡面不可以 import 到這個 Module，否則還是會在應用程式啟動時就載入。</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;在 Angular 應用程式一載入時，預設會將所有的 Module 一次全部載入，但如果今天應用程式規模很大，或是某些 Module 中需要載入的東西過多，就會拖到整個應用程式的載入時間。&lt;/p&gt;
&lt;p&gt;為了解決這個問題，Angular 有針對 Module 提供 Lazy Loading 的功能，簡單來說就是當需要此 Module 的時候再進行載入，如此就不會影響到整個應用程式的效能。&lt;/p&gt;</summary>
    
    
    
    <category term="Angular" scheme="https://andyhung0723.github.io/categories/Angular/"/>
    
    
  </entry>
  
  <entry>
    <title>探討 Angular Module</title>
    <link href="https://andyhung0723.github.io/2022/05/28/angular-module/"/>
    <id>https://andyhung0723.github.io/2022/05/28/angular-module/</id>
    <published>2022-05-28T12:06:08.000Z</published>
    <updated>2026-11-13T13:54:48.162Z</updated>
    
    <content type="html"><![CDATA[<p>Angular 本身的設計概念就是使用模組化的機制，Module (模組) 是組成 Angular 應用程式的基本單位，每個 Angular 專案最開始都會有一個模組當作程式進入點，稱為<strong>根模組(Root Module)</strong> 。透過 Angular CLI 創建的專案會將此根模組命名為<code>AppModule</code>，並放在<code>app.module.ts</code>檔案中。</p><p>也可以將有相同特性的功能拆出來，組合成不同的模組，各個模組間依程式架構相互引用，組合成 Angular 應用程式。模組中可以透過設定的方式，定義此模組中包含的 components、directives、pipes 等，以及其他與模組相關的屬性，以下我們就來研究一下 Angular Module 的使用方式以及使用情境。</p><span id="more"></span><h2 id="組成"><a href="#組成" class="headerlink" title="組成"></a>組成</h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">  <span class="attr">declarations</span>: [</span><br><span class="line">    <span class="title class_">AppComponent</span>,</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">imports</span>: [</span><br><span class="line">    <span class="title class_">BrowserModule</span>,</span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">providers</span>: [],</span><br><span class="line">  <span class="attr">bootstrap</span>: [<span class="title class_">AppComponent</span>]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>定義模組的檔案中會包含<code>@NgModule</code>，用來定義模組的設定。主要包含以下幾個屬性：</p><h3 id="declarations"><a href="#declarations" class="headerlink" title="declarations"></a>declarations</h3><p>用來宣告此模組中包含的 components、directives、pipes。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">declarations</span>: [</span><br><span class="line">  <span class="title class_">UserComponent</span>,</span><br><span class="line">  <span class="title class_">CustomPipe</span>,</span><br><span class="line">  <span class="title class_">FileDirective</span></span><br><span class="line">],;</span><br></pre></td></tr></table></figure><ul><li>若使用<code>ng generate</code> 指令來產生物件，Angular CLI 會自動幫你把物件加入 declarations 中。</li></ul><h3 id="imports"><a href="#imports" class="headerlink" title="imports"></a>imports</h3><p>想要額外載入的 module，載入後就可以使用該 module 中 exports 的物件。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">imports</span>: [</span><br><span class="line">  <span class="title class_">BrowserModule</span>,</span><br><span class="line">  <span class="title class_">UserModule</span></span><br><span class="line">],</span><br></pre></td></tr></table></figure><ul><li>如上例，只要 import UserModule，模組內就可以使用 UserModule 中 export 的所有物件。</li><li>根模組必須要 import BrowserModule。</li><li>其他模組必須要 import CommonModule。</li><li>只要是用 CLI 建立的，上述兩項都會自動 import。</li></ul><h3 id="exports"><a href="#exports" class="headerlink" title="exports"></a>exports</h3><p>要匯出給其他模組使用的物件。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">declarations</span>: [</span><br><span class="line">  <span class="title class_">UserComponent</span>,</span><br><span class="line">  <span class="title class_">CustomPipe</span>,</span><br><span class="line">  <span class="title class_">FileDirective</span></span><br><span class="line">],;</span><br><span class="line"><span class="attr">exports</span>: [</span><br><span class="line">  <span class="title class_">UserComponent</span></span><br><span class="line">],</span><br></pre></td></tr></table></figure><ul><li>要 export 的物件必須存在於 declarations 或 import 的 Module 中才可以。</li><li>上例 export 的只有 UserComponent，因此引入此 module 的模組只可使用 UserComponent。</li></ul><h3 id="providers"><a href="#providers" class="headerlink" title="providers"></a>providers</h3><p>宣告可以依賴注入的 service，整個應用程式都可以使用到此處宣告的 service。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">providers</span>: [</span><br><span class="line">  <span class="title class_">UserService</span></span><br><span class="line">],</span><br></pre></td></tr></table></figure><p>關於 providers 會再整理一篇文章進行探討。</p><h3 id="bootstrap"><a href="#bootstrap" class="headerlink" title="bootstrap"></a>bootstrap</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">bootstrap</span>: [<span class="title class_">AppComponent</span>],</span><br></pre></td></tr></table></figure><p>定義根元件，作為應用程式啟動後預設讀取的元件，只有根模組需要定義此屬性，一般不太需要更動。<br><br></p><h2 id="使用情境"><a href="#使用情境" class="headerlink" title="使用情境"></a>使用情境</h2><p>Module 用法除了最基本會有的<strong>根模組(Root Module)</strong> 外，常見的還有以下兩種用法：</p><h3 id="Feature-Module"><a href="#Feature-Module" class="headerlink" title="Feature Module"></a>Feature Module</h3><p>其實就是最常見、第一個會想到使用 Module 的情境。將應用程式中你認為可以額外拆出來撰寫成一個功能的程式片段，拆出來成為一個 Module，就會稱它為<code>Feature Module</code>。</p><p>例如假設今天要實作一個網頁聊天室，聊天室可以傳送的訊息種類分為文字、檔案、圖片、貼圖等，我們就可以把傳送的**「訊息」** 拆一個 MessageModule，裡面包含 TextComponent、FileComponent、ImageComponent … 與其他串接的 Service 等。</p><h3 id="Shared-Module"><a href="#Shared-Module" class="headerlink" title="Shared Module"></a>Shared Module</h3><p>在 Angular 中常常會遇到很多物件(component、directive、pipe)一直被重複使用，此時為了不讓這些物件散落各地，還要讓 Module 一直引用來引用去，通常可以建立一個<code>Shared Module</code>來統一管理這些物件，要使用這些物件的 Module 只需要匯入一個<code>Shared Module</code>就可以了。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">@<span class="title class_">NgModule</span>(&#123;</span><br><span class="line">  <span class="attr">declarations</span>: [</span><br><span class="line">    <span class="title class_">TableComponent</span>, </span><br><span class="line">    <span class="title class_">PagerComponent</span>, </span><br><span class="line">    <span class="title class_">PaginationComponent</span></span><br><span class="line">  ],</span><br><span class="line">  <span class="attr">exports</span>: [</span><br><span class="line">    <span class="title class_">TableComponent</span>, </span><br><span class="line">    <span class="title class_">PagerComponent</span>, </span><br><span class="line">    <span class="title class_">PaginationComponent</span></span><br><span class="line">  ],</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">SharedModule</span> &#123;&#125;</span><br></pre></td></tr></table></figure><ul><li>如上例，其他模組只需要 import <code>SharedModule</code> 就可以使用裡面的所有物件。</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;Angular 本身的設計概念就是使用模組化的機制，Module (模組) 是組成 Angular 應用程式的基本單位，每個 Angular 專案最開始都會有一個模組當作程式進入點，稱為&lt;strong&gt;根模組(Root Module)&lt;/strong&gt; 。透過 Angular CLI 創建的專案會將此根模組命名為&lt;code&gt;AppModule&lt;/code&gt;，並放在&lt;code&gt;app.module.ts&lt;/code&gt;檔案中。&lt;/p&gt;
&lt;p&gt;也可以將有相同特性的功能拆出來，組合成不同的模組，各個模組間依程式架構相互引用，組合成 Angular 應用程式。模組中可以透過設定的方式，定義此模組中包含的 components、directives、pipes 等，以及其他與模組相關的屬性，以下我們就來研究一下 Angular Module 的使用方式以及使用情境。&lt;/p&gt;</summary>
    
    
    
    <category term="Angular" scheme="https://andyhung0723.github.io/categories/Angular/"/>
    
    
  </entry>
  
</feed>
