[實作筆記] 形象站滿版背景影片(一):前端靜態資源放哪裡

前情提要

做形象站,Hero 要放一支滿版自動播放的背景影片,第一個冒出來的問題是「影片放哪裡」。

這個問題帶出了前端靜態資源的兩種擺法:public/src/assets/。對一般人看起來只是資料夾名字不同,但對工程師來說,兩者的機制差很多。

做形象站 Hero 背景影片的前置研究。完整的流量估算與播放器選型,見下一篇

素材放哪:public/ vs src/assets

對一般人來說看起來只是資料夾名字不同,但對這裡有蠻多的細節,我們來逐一分析。

首先要了解兩個時間點:

  • 編譯期(Build Time):網站還沒上線前,可以將一些資源優化打包減少不必要的流量,或是使用雜湊命名來避免快取問題。
  • 執行期(Runtime):網站上線後,使用者實際使用的期間。程式在這個階段才真正執行,才能動態取得資源、回應使用者的操作。

src/assets/ — 打包工具接管

現代主流網站打包工具(Vite / Webpack)會在編譯期處理這些檔案:

  • 雜湊檔名:輸出 bg.a1b2c3d4.mp4,URL 跟著內容變,瀏覽器可以放心永久 cache(Cache-Control: immutable)——改了檔案雜湊就換,訪客自動抓新的
  • 可能優化:圖片壓縮、小檔案 inline 成 base64 等
  • 追蹤依賴:沒有被 import 的檔案,build 產出裡就不會出現

限制一import 是編譯期的靜態行為,URL 在 build 時就決定了,沒辦法在 runtime 動態組字串——更不可能從資料庫讀一個 URL 出來用。

限制二:打包工具適合處理 JS、CSS、小圖,遇到影片這種大檔案,build 時間拉長,而且影片可壓縮或優化的效果有限,過一手只是浪費。

public/ — 繞過打包工具

這裡的資源不會被打包工具處理,本質跟早期 Apache / Nginx 放一個靜態資料夾直接 serve 檔案是同一件事——收到請求,原樣回傳。快取責任落在「伺服器那層」:早期要自己設 cache header,現代部署平台(Vercel、Netlify、Cloudflare Pages)會自動推到 Edge Network 幫你卸載流量——但這是平台做的,不是框架。

URL 永遠是 /你放的路徑,開發時字串直接用不用 import

1
2
<video src="/hero.mp4" />     ← 寫死字串
<video src={dbValue} /> ← 從資料庫來的字串,也走得通

Next.js 本身真正在 framework 層處理靜態資源的是 next/image:server side 做圖片壓縮、格式轉換、依裝置裁切,回傳正確的 cache header。public/ 它不碰。

判斷比較

| | src/assets/ | public/ |
| — | — | — |
| 引用方式 | import,編譯期靜態 | 字串 URL,runtime 動態 |
| 快取 | 自動雜湊,可放心 immutable | 手動管理,或靠部署平台預設值 |
| 大檔案 | 不適合(影片、字型) | 適合 |
| 適合 | Icon、logo、小圖 | 後台可換的媒體、使用者貼的 URL |

我們的例子是背景影片,幾乎都是「後台可換、runtime 才知道 URL」的需求 → 判斷上選擇 public/ 較為適合。

參考

小結

  • src/assets/ 交給打包工具管,享有自動雜湊快取,但只能靜態 import、不適合大檔案。
  • public/ 繞過打包工具,直接 serve,URL 是字串、runtime 拿來用都沒問題。
  • 影片、字型這類大媒體放 public/;icon、logo 等小圖用 src/assets/
  • 換 CDN 只需換 URL 字串,不用動程式碼。

(fin)

[AI生成] 20260612 科技周報

AI 週報配圖

本周要點

其他訊息

(fin)

[AI生成] 20260610 科技周報

AI 週報配圖

本周要點

  • 秘密向 SEC 提交 S-1 註冊聲明草案:OpenAI 宣布已向美國證券交易委員會(SEC)秘密提交了 S-1 格式的招股說明書草案,準備進行首次公開募股(IPO)。這標誌著該公司在商業化與資本市場化道路上的重大里程碑。more
  • 智能時代的產業政策:OpenAI 提出了針對智能時代的產業政策藍圖,強調需要建立強大的 AI 基礎設施,包括能源、晶片及數據中心。此政策旨在確保國家競爭力並促進 AI 技術的民主化與安全發展。more
  • 築夢:為更具幫忙能力的 ChatGPT 提供更好的記憶力:OpenAI 推出名為「Dreaming」的新技術,旨在升級 ChatGPT 的記憶機制。透過在後台進行「夢境」般的離線整合,ChatGPT 能更有效率地整理與回顧過往的對話上下文,提供更具連貫性且個人化的互動體驗。more
  • 旨在造福大眾:我們的計劃:OpenAI 發表了其未來的發展計劃,重申確保通用人工智能(AGI)造福全人類的使命。該計劃詳細說明了治理結構的優化以及如何將 AI 技術帶來的經濟價值公平地分配給社會各界。more
  • 介紹 GPT-Rosalind 的全新功能:OpenAI 宣布為 GPT-Rosalind 引入全新功能,提升其在科學研究與複雜邏輯推理方面的表現。這次更新將使該模型能更有效地協助生物學及其他前沿科學領域的研究人員進行探索。more
  • 推出 OpenAI 經濟研究交流平台:OpenAI 成立了「經濟研究交流平台(Economic Research Exchange)」,旨在與全球學術界和政策制定者合作,共同研究 AI 對勞動力市場、生產力以及整體經濟結構的深遠影響。more
  • 智能時代的生物防禦:本文探討了在 AI 快速發展的時代下,如何利用先進模型來強化全球生物防禦系統。OpenAI 強調了制定安全防護措施的重要性,以防止技術被濫用,同時利用 AI 預防與應對潛在的生物安全威脅。more

其他訊息

(fin)

[實作筆記] 形象站滿版背景影片(二):流量、CDN 與播放器選型

前情提要

Hero 要放一支滿版自動播放的背景影片。

Hero 區塊是網頁最頂部的全版區塊,通常含標題、說明文字與背景,是訪客進站看到的第一眼。

素材要放哪,已在上一篇整理好了,結論是放 public/,URL 字串直接用。

這篇專注在另外兩個問題:

  1. 流量控管:滿版自動播放背景影片是首頁最吃流量的東西,怎麼估、怎麼省?
  2. UI 體驗:背景影片要無控制列、自動播放、靜音、循環——原生 <video> 還是嵌入 YouTube/Vimeo?

自存影片:會吃多少流量?

會,而且滿版自動播放的背景影片,是整頁最吃流量的東西

粗估一下:一支壓到 SD 的背景影片約 3.5MB,每個訪客每次載入首頁就抓一次(瀏覽器會快取,回訪者不重抓)。

1
3.5MB × 10,000 次造訪/月 ≈ 35GB/月

對小型品牌站通常還在額度內,但要注意兩件事:

  1. 行動裝置上,這 3.5MB 是吃訪客自己的行動數據,UX 不友善。
  2. 影片越大支越可怕,HD 1080p 動輒 12MB 起跳。

重點觀念:走 CDN ≠ 不算流量

很多人以為「丟到平台、平台有 CDN」就沒事了。

以主流部署平台來說,public/ 的靜態檔確實會由它的 Edge Network(CDN)快取分送——但傳輸量仍然計入你的方案額度

CDN 解決的是「分送速度與快取」,不是「免費流量」。要真正卸載流量,得換 host。

要省流量:CDN / 影音 host 比較

影片放在 public/ 的話,流量算在部署平台的額度裡。

以我們用的平台 Vercel 免費方案只有 100GB/月,一支背景影片流量大的時候很快就吃光。

解法是把影片搬到外部 host,讓別人的伺服器去扛流量。

好消息是,只要程式碼只用 URL 字串引用影片,換 host 就是換那個字串,不用改程式碼

1
2
3
4
5
// 原本放 public/
<video src="/hero.mp4" />

// 搬到 R2 後,只改這一行
<video src="https://pub-xxx.r2.dev/hero.mp4" />

兩條路線:

路線一:自己存,外部 CDN 來送(Cloudflare R2

把影片傳到 R2,egress(流出流量)免費,只付儲存費($0.015/GB/月)。一支 5MB 影片幾乎是 $0,部署平台那邊完全不計這筆流量。

路線二:讓別人的平台吸收(Vimeo/Youtube)

影片上傳到 Vimeo,你的伺服器完全不出流量,由 Vimeo 負責送給訪客。代價是多了第三方依賴,免費方案有上傳量限制。

方案 流量誰扛 備註
Cloudflare R2 R2(egress 免費) 自己管檔案,換 URL 即可
Cloudflare Stream / Mux 平台 專業影音串流,自動轉檔、自適應位元率
Cloudinary 平台 媒體優化 + CDN
Vimeo Vimeo 免費方案有上傳限制,背景模式乾淨
YouTube 嵌入 YouTube(完全免費) 有播放器外觀問題(下節詳述)

形象站的滿版背景,通常不會用 YouTube,原因看下面。

YouTube 當「無播放器」背景?hack 與代價

YouTube 這麼主流,能不能拿來當乾淨背景?

沒有官方乾淨方案,主流做法都是 hack,而且 YouTube 近年反而把「藏品牌」收得更緊。

做法是 IFrame Player API + 參數 + CSS:

1
autoplay=1&mute=1&loop=1&playlist=VIDEO_ID&controls=0&playsinline=1&rel=0&disablekb=1&iv_load_policy=3
1
2
3
4
5
6
7
8
/* 把 iframe 放大超出視窗、置中裁切,藏掉黑邊與殘留 UI */
.bg-wrap { position: absolute; inset: 0; overflow: hidden; }
.bg-wrap iframe {
position: absolute; top: 50%; left: 50%;
width: 150vw; height: 150vh; /* 刻意超出 */
transform: translate(-50%, -50%);
pointer-events: none; /* 防止點到跳出控制列 */
}

代價很實際:

  • modestbranding 已被 YouTube 淡化/移除,載入、暫停、結束仍可能閃一下 logo/標題
  • 單片循環要用 loop=1&playlist=ID 的 trick,接點會黑屏跳一下(要用 API seekTo(0) 才順)。
  • 16:9 硬裁成滿版 → 邊緣被切掉
  • 比原生 <video> 重很多(要載播放器 JS、追蹤 cookie,除非用 youtube-nocookie)。
  • 手機(尤其 iOS)自動播放不穩
  • 「完全藏品牌」本身遊走在 ToS 邊緣。

真正乾淨的主流解

1. Vimeo 背景模式

Vimeo 的嵌入支援 background=1 參數,這是官方為背景影片設計的模式:自動播放、循環、靜音、全程無控制列、無品牌

1
https://player.vimeo.com/video/VIDEO_ID?background=1&muted=1&autoplay=1&loop=1

要 iframe 又要乾淨,這才是該選的,比 YouTube hack 乾淨太多。

2. 影音 CDN 的 mp4 + 原生 video

把影片放 Stream / Mux / R2,拿到真正的 mp4/HLS URL,用原生 <video> 播。

最乾淨、最可控,也最好做手機降級(poster、preload、小螢幕只給圖)。

架構建議:媒體以 URL 為主

把這些湊起來,得到一個簡單原則:渲染層不要綁死 host。

  • 媒體只存一個 URL 字串(哪來的都行:自家 public/、R2、Mux、Vimeo iframe)。
  • 範例/預設素材放 public/,跟使用者貼的網址走同一條路徑。
  • 正式上線要換成 CDN?貼上新 URL 即可,不用改程式碼。
  • 要支援 iframe 型(Vimeo/YouTube)就多開一種「媒體類型」,渲染分流到 iframe,原生影片仍走 <video>

這樣早期可以自存 demo、之後無痛換成專業影音 CDN,決策成本最低。

參考

小結

  • 滿版自動播放背景影片最吃流量;CDN 加速 ≠ 免費流量,傳輸仍算額度。
  • 省流量靠換 host:R2(egress 免費)/ Stream / Mux / Cloudinary。
  • YouTube 無播放器背景只能 hack,缺點一堆;要 iframe 乾淨解請用 Vimeo background=1
  • 最乾淨:影音 CDN 的 mp4 + 原生 <video>
  • 架構上讓媒體「只認 URL」,換 host 就是換字串,不用動程式碼。

(fin)

[AI生成] 20260605 科技周報

AI 週報配圖

本周要點

其他訊息

(fin)

[實作筆記] 盤點與清理自訂網域的 Email DNS 殘留(用郵件 header 當偵探)

前情提要

這幾天整理 Cloudflare 的 DNS,看到幾筆我沒有記憶也不理解的記錄:

1
send.marsen.me   MX   feedback-smtp.ap-northeast-1.amazonses.com

Amazon SES?我什麼時候設過?還在用嗎?敢不敢刪?

不確定就不要亂刪 DNS——刪錯一筆,輕則信進垃圾桶,重則收不到信。所以乾脆把整個 marsen.me 上的 email 服務盤點一次,搞清楚每一筆 DNS 到底在幹嘛。

第一步,列出 DNS Record

把 DNS 裡跟 email 有關的記錄抓出來,對應到服務:

| 服務 | 相關 DNS 記錄 |
| —— |————–|
| Cloudflare Email Routing | marsen.me MX(route1-3.mx.cloudflare.net) |
| Brevo(原 Sendinblue) | brevo1/2._domainkey CNAME |
| Resend | resend._domainkey TXT |
| Amazon SES | send.marsen.me MX + SPF |

四套服務、一堆 DKIM/SPF/MX,光看 DNS 根本分不出哪些還在使用,用途為何?

第二步,理解 DNS Record

可以參考文章最末的參考資料,這裡簡單說明 MX 與 SPF,以後有機會再進一步說明

MX: 告訴別人「寄到 @你的網域 的信,送去哪台伺服器,

你家的收件信箱地址,別人寄東西來才送得到。

SPF / DKIM = 你寄信時的防偽印章和授權書

證明「這封信真的是你(或你授權的服務)寄的」,防止被當垃圾或冒名

所以一個純發信的服務(像 Brevo、Resend),只需要 DKIM 印章,根本不需要 MX。這個觀念是後面判讀的基礎。

補充:SPF 和 DKIM 的內容本體都是 TXT,但 DKIM 有兩種發布方式——
一種像 Resend 是把公鑰直接寫成 TXT 給你貼;
另一種像 Brevo 則是給你一筆 CNAME,把 brevoX._domainkey 委派指向它自家的 DNS,公鑰放在它那邊,方便它自己輪替金鑰。
所以上面表格裡 Brevo 是 CNAME、Resend 是 TXT,但做的是同一件事。

寄收信測試

我們可以查看郵件 header——它記錄了一封信實際走過的每一站。

方法很簡單:寄一封測試信給自己,打開「顯示原始郵件」看 header。

我用 [email protected] 寄一封信給自已

1
2
3
4
5
Message-Id: <[email protected]>
Received: from hb.d.sender-sib.com (...)
DKIM-Signature: ... d=marsen.me s=brevo2 ... → PASS
Feedback-ID: ...:Sendinblue
Return-Path: <[email protected]>

sendinbluesender-sib(SendInBlue 的縮寫)、s=brevo2 的 DKIM 簽章——這封信百分之百走 Brevo 發出。

s=brevo2 還正好對應到我 DNS 裡的 brevo2._domainkeyBrevo 確認在用。

同一封信,還證明了收信端

更妙的是,這封我寄給 [email protected] 的信,被轉發回我 Gmail,header 把收信路徑也記下來了:

1
2
3
4
Received: by cloudflare-email.net       → Cloudflare Email Routing 收到
X-Forwarded-To: [email protected]
X-Forwarded-For: [email protected] [email protected]
Delivered-To: [email protected]

一封信同時驗證了兩端:Brevo 發信Cloudflare Email Routing 收信並轉發 → 進 Gmail。

那「收信」到底是怎麼運作的?

順著 header 就看懂了,我的收信是 Cloudflare Email Routing

1
2
3
4
5
別人寄到 [email protected]
→ marsen.me 的 MX 指向 Cloudflare(route1-3.mx.cloudflare.net)
→ Cloudflare Email Routing 收到
→ 依轉發規則(Routes)轉寄
→ 我的真實 Gmail

重點:Cloudflare Email Routing 是轉發,不是信箱。

它不存信,收到就立刻轉寄到你真正的 Gmail。所以 @marsen.me 沒有獨立的信箱空間,所有信最終都進同一個 Gmail。

整套自訂網域信箱長這樣:

1
2
3
            ┌─ 收信 → Cloudflare Email Routing(MX)→ 轉發 ┐
@marsen.me ─┤ ├→ Gmail
└─ 寄信 ← Brevo SMTP relay ← Gmail「以 admin@ 寄」┘

用免費服務,把 Gmail 變成 @marsen.me 的網域信箱。

這就是我免費達成私有 domain 信件寄收的作法,但是要注意 Brevo 有每日 300 封信的使用上限

盤點結果

三重交叉查證(程式碼 grep、n8n 備份、郵件 header)之後:

| 服務 | 狀態 | 證據 |
| ——|——|——|
| Cloudflare Email Routing | ✅ 在用 | header 轉發路徑 |
| Brevo | ✅ 在用 | header 的 sendinblue / brevo2 簽章 |
| Resend | ✅ 在用 | 電商專案發訂單信,程式碼有引用 |
| Amazon SES | ❌ 殘留 | 任何地方都找不到使用,連 SES 驗證記錄都沒有 |

SES 是當初設定網域信箱時評估過的備選方案(按量計費、便宜但設定複雜),最後選了 Brevo,

但 AWS 用的 send.marsen.me 的 MAIL FROM 記錄留下來沒清。

為什麼在用的 Brevo 沒有 MX,沒用的 SES 反而有?

這題剛好回扣前面「收信才用 MX」的觀念,但有個例外:

  • Brevo:純發信,靠 DKIM + SPF 驗證授權,不需要 MX。所以它在用,卻沒有 MX。
  • SES:那個 send.marsen.me 的 MX 不是收一般信,而是 SES 的「custom MAIL FROM」機制要求的,用來接收退信/投訴回報(bounce/complaint)。

諷刺的是:沒在用的 SES 因為特殊機制留了 MX,在用的 Brevo 因為純發信反而沒有 MX。

光看「有沒有 MX」完全判斷不出哪個在用。

安全清理

確認 SES 是殘留後,要刪的只有兩筆(name 都是 send.marsen.me)。

刪之前先把完整內容記下來——理論上它一定沒用了,但留個底,萬一哪天要恢復可以照著重建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ── 被刪除的 SES 殘留記錄(刪除日:2026-06-04,留供日後恢復)──

# 第一筆:SES custom MAIL FROM 的 bounce 接收
Type = MX
Name = send.marsen.me
Content = feedback-smtp.ap-northeast-1.amazonses.com
Priority = 10
Proxy = DNS only
TTL = 1 hour

# 第二筆:SES 的 SPF
Type = TXT
Name = send.marsen.me
Content = "v=spf1 include:amazonses.com ~all"
Proxy = DNS only
TTL = 1 hour

註:若真要復原 Amazon SES 寄信,光補這兩筆 DNS 不夠,還得回 AWS Console(ap-northeast-1 東京)重新驗證 identity 與 custom MAIL FROM。這兩筆只是當時設定留下的 DNS 半成品。

小結

盤點 email DNS 殘留,兩個心法:

  1. 分清收信和發信——MX 是收信,SPF/DKIM 是發信驗證。看到一筆記錄先問它管的是收還是發。
  2. 用郵件 header 當偵探——dashboard 會騙人,header 不會。寄封測試信,原始 header 裡寫得清清楚楚這封走了哪些服務。記得用網域地址寄,別用個人信箱,不然測了個寂寞。

殘留通常來自「評估過但沒採用的方案」——設定設了一半,淘汰後忘了清。盤點一次,把死記錄清掉,DNS 才乾淨。

補充:DNS 記錄類型速查

記錄 說明
MX 收信路由。告訴外部郵件伺服器「寄到這個網域的信,應該送到哪台 SMTP 伺服器」,數字優先度越小越優先,可設多筆做備援
TXT 純文字記錄,DNS 裡的萬用槽。SPF、DKIM 公鑰、網域所有權驗證都塞這裡
CNAME 別名記錄。把一個 subdomain 指向另一個 hostname,由對方那端負責最終解析。根網域(marsen.me 本身)不能用
SPF 發信授權白名單,格式寫在 TXT 裡(v=spf1 ...)。聲明哪些 IP 或服務有資格以這個網域寄信,收件方用來驗發件 IP
DKIM 郵件防偽簽章。發信服務用私鑰簽章,公鑰掛在 DNS(TXT 或 CNAME 委派),收件方取公鑰驗簽,確認內容未被竄改
A 最基本的記錄。把網域直接對應到一個 IPv4 位址
AAAA 同 A,對應的是 IPv6 位址
NS 管轄聲明。指定這個網域的 DNS 問題,由哪幾台 Name Server 負責回答

參考

(fin)

[實作筆記] 更新自架在 GCP VM 上的 n8n(Docker 版)

前情提要

自架 n8n 跑在 GCP VM 的 Docker container,
某天備份 log 出現這行:

1
Error tracking disabled because this release is older than 6 weeks.

意思是 n8n 的 release 超過六週就會關掉錯誤追蹤,提醒你該更新了。
趁機整理一下 Docker 版 n8n 的更新流程。


更新前先確認現況

確認目前版本

1
2
docker exec n8n n8n --version
# 2.16.1

確認 container 設定

更新要重建 container,所以要先抓出原本的設定:

1
2
3
4
5
6
7
8
9
docker inspect n8n --format '{{json .HostConfig.PortBindings}}'
# {"5678/tcp":[{"HostIp":"","HostPort":"5678"}]}

docker inspect n8n --format '{{range .Mounts}}{{.Source}}:{{.Destination}}{{end}}'
# /home/user/.n8n:/home/node/.n8n

docker inspect n8n --format '{{range .Config.Env}}{{println .}}{{end}}'
# N8N_SECURE_COOKIE=false
# ...(其他是 image 預設的,不用帶)

重點是找出三個東西:portbind mount 路徑自己設的 env


更新三步驟

Step 1:pull 最新 image

1
docker pull docker.n8n.io/n8nio/n8n

Step 2:停掉舊 container

1
docker stop n8n && docker rm n8n

這時候 n8n 停機,資料不會消失,因為資料在 VM 本地的 bind mount 目錄,
跟 container 的生命週期完全無關。

Step 3:用相同設定重新啟動

1
2
3
4
5
6
7
docker run -d \
--name n8n \
--restart unless-stopped \
-p 5678:5678 \
-v /home/user/.n8n:/home/node/.n8n \
-e N8N_SECURE_COOKIE=false \
docker.n8n.io/n8nio/n8n

-v 的路徑換成你自己的 bind mount 路徑,env 只帶你自己加的就好。


驗證

1
2
docker exec n8n n8n --version
docker ps | grep n8n

確認版本號,確認 container 狀態是 Up,完成。


補充:備份

更新前要不要備份?

如果你有設 bind mount,資料就在 VM 本地,container 停掉不影響。
但如果更新後 n8n 有 migration 問題,舊 DB 可能回不去。

保險做法是更新前先手動跑一次備份:

1
2
3
4
5
6
7
# 匯出所有 workflow
docker exec n8n n8n export:workflow --all --pretty \
--output=/home/node/.n8n/exports/workflows/

# 匯出所有 credentials
docker exec n8n n8n export:credentials --all --pretty \
--output=/home/node/.n8n/exports/credentials/

或者搭一個 cron job 每天自動備份、git push,就不用每次更新前手動跑:

1
2
# crontab -e
0 3 * * * /home/user/n8n-backup/backup.sh >> /var/log/n8n-backup.log 2>&1

小結

Docker 版 n8n 更新流程:

  1. docker pull — 拉新 image
  2. docker stop n8n && docker rm n8n — 移除舊 container
  3. docker run — 用相同設定重建

停機時間大約 30 秒。
關鍵是 bind mount:資料住在 VM,不住在 container,container 砍掉重練資料不受影響。

(fin)

[工具筆記] Prime Token vs MPG:兩種台灣電商金流模式的本質差異

前情提要

最近在電商專案要把虛構金流換成真實串接,比較了 TapPay、綠界、藍新三家。

比著發現原來存在著兩種金流串接的模式。

  • Prime Token 模式:TapPay、Stripe、Braintree
  • MPG(Merchant Payment Gateway) 模式:綠界 ECPay、藍新 NewebPay

兩種模式選錯,後面整個訂單系統的設計都會錯。


本質差異就一個問題:卡號從哪走?

兩種模式的根本問題只有一個:敏感卡號(PAN + CVV)的傳遞路徑

MPG 型金流(綠界、藍新跳轉)對消費者反而更透明——畫面明確跳到金流商的頁面,消費者看得出來自己在哪。

但是在使用者體驗上,會多一個斷點,以電商來說會有轉換率的問題

Prime 型(TapPay iframe)的取捨是體驗好但透明度低,信任靠的是商家品牌,不是技術可見性。

而這是一個取捨。


實作細節

Prime Token 的卡號欄位內嵌結帳頁(實際是 iframe,能改邊框字體但限制多)。

整個結帳流程在你自己的頁面,設計語言、外觀風格一致。

MPG 直接跳到金流方頁面,你的品牌設計到那一刻全部斷掉

但好處也很實際:同一個金流頁面能直接接信用卡 + ATM + 超商代碼 + LINE Pay。

兩者的開發量比較

Prime Token 你寫的東西:

  • 前端 SDK 載入 + mount 欄位
  • 後端一支 charge API
  • 一個結果頁

MPG 你多寫的東西:

  • 表單產生器(含簽章演算法)
  • 自動 submit 的轉址頁
  • NotifyURL endpoint(驗章 + 冪等 + 更新訂單,這支是核心)
  • ReturnURL endpoint(使用者回站只看結果,不可以當付款依據)
  • 訂單狀態機要多 awaiting_payment
  • 對帳邏輯(callback 沒到怎辦?要定時 query 嗎?)

MPG 看似簡單,實際工程量比 Prime Token 大,主要是 callback 的 edge case 多

補充: PCI DSS 是什麼 ?

Payment Card Industry Data Security Standard,簡稱 PCI DSS。

信用卡組織(Visa、Mastercard 等)聯合制定的資安標準,規定任何「碰到卡號」的系統都要符合一堆安全要求。

核心概念:碰到卡號的範圍越小,你要過的關越少。

實務上只有金流商或大型電商會去取得這種認証,一般而言小型電商還是透過第三方金流來實現交易。


小結

  • 兩種模式的本質差異是卡號的傳遞路徑:Prime Token 走 SDK iframe,MPG 走表單轉址
  • 信任是最難的

(fin)

[實作筆記] LINE Messaging API 用量查詢:免費額度怎麼看,以及為什麼通知會停止

前情提要

用 LINE Bot 做系統通知,結果某天發現通知完全停了,重啟也沒用。
查了一圈才發現根本原因不是程式問題,這篇記錄怎麼查用量、以及為什麼停的。


問題現象

LINE Bot 的 push 通知在某個時間點之後完全靜默。
程式沒報錯,因為程式碼裡的 push 用了 .catch(() => {}) 吃掉所有錯誤:

1
2
3
async function push(text: string) {
await lineClient.pushMessage(ALLOWED_USER_ID, msg).catch(() => {})
}

靜默失敗,完全看不出來哪裡出問題。


怎麼查用量

LINE 的用量統計不在 Developers Console,要去 LINE Official Account Manager

  1. 打開 manager.line.biz
  2. 選你的 Official Account
  3. 左側 → 分析訊息

可以看到:

欄位 說明
合計(所有訊息) Reply + Push 總和
Push 主動推播的則數
Reply 回覆訊息的則數

可以選日期範圍,最長 60 天。


免費額度是多少

LINE Messaging API 免費方案每月有 500 則免費訊息(Push + Reply 合計)。

超過之後每則需要付費,或者訊息會被擋下來(依帳號設定而定)。

500 則聽起來很多,但如果 Bot 跑 AI 對話,Claude 回應很長,常常一次就切成好幾則 push(每則上限 5000 字),很快就會耗光。


這次的真正原因

查完用量才發現:5/1 用了 141 則,5/2 用了 59 則,5/3 之後全部是 0。

5/3 之後不是「發了但被擋」,是根本沒有觸發 webhook。

原因是 LINE Bot 用 Webhook 模式,需要一個對外的 HTTPS URL。
我的架構是:

1
LINE 伺服器 → HTTPS Webhook URL → Cloudflare Tunnel → 本機 Express server

Cloudflare Tunnel 的 launchd service 在 5/3 掛掉,LINE 打不到 webhook,所以什麼都沒發生。


Telegram 為什麼更穩

Telegram 用 Long Polling 模式,bot 主動去 Telegram 伺服器拉訊息,不需要對外開放任何 URL。

LINE Telegram
連線模式 Webhook(需要 tunnel) Long Polling(不需要)
斷線風險 tunnel 掛、IP 變、PORT 未開 幾乎沒有
免費額度 500 則/月 無限制

如果是用來做系統通知(不可中斷),Telegram 比 LINE 穩定很多。


小結

  • LINE 用量在 LINE Official Account Manager → 分析 → 訊息
  • 免費方案 500 則/月,用完靜默失敗
  • Webhook 模式依賴 tunnel,tunnel 掛掉通知就停
  • 對穩定性要求高的通知場景,Telegram Long Polling 更適合

(fin)

[AI生成]20260505 周報

本周要點

其他訊息

(fin)