想要親手打造一款真正能上線運行的 以太坊 DApp,不僅得懂智能合約,更要釐清「整體應用程式架構」。本文將帶你在不超過 15 分鐘的閱讀時間裡,迅速建立 去中心化應用 的完整思維模型,並給出可落地的設計範例與程式碼片段。
為什麼傳統架構無法直接套用?
在傳統 Web2 世界,後端伺服器一手掌握資料庫與商業邏輯,前端僅需透過 API 請求即可。而 以太坊 DApp 加入了「區塊鏈」這條不可變的共用資料層,逼迫我們重新劃分前端、後端、鏈上三者的權責邊界。
👉 全方位 Ethereum 開發資源一次打包,30 天進階為 DApp 架構師。
核心概念:分層拆分
- 鏈上層(On-chain)
智能合約負責資產邏輯與關鍵狀態。
關鍵詞:智能合約、部署、gas 優化、升級代理。 - 中間層(Off-chain Service)
有時仍需中心化伺服器:補足鏈上無法完成的密集計算、大量儲存或隱私需求。
關鍵詞:索引服務、預言機、批次程式、自動化調度。 - 表現層(Client)
瀏覽器或手機端,透過 Web3 函式庫與錢包互動。
關鍵詞:web3.js、ethers.js、簽章授權、離線交易。
第一種方案:無伺服器 DApp(純前端 + 鏈上)
這是最純粹的 去中心化應用 形態:
- 前端直接呼叫 Infura/Alchemy RPC 端點,省去自建節點。
- 前端打包後放置於 IPFS + ENS,達成檔案與程式碼的去中心化。
檔案內容過大時,可用 Swarm 或 IPFS 儲存,再於合約內記錄
contentHash即可。注意:IPFS 節點可能因資源回收而刪除資料,建議透過 Pinning Service 長效保存。
常見程式碼片段(查詢交易)
import Web3 from 'web3';
const web3 = new Web3('https://mainnet.infura.io/v3/YOUR_KEY');
(async () => {
const block = await web3.eth.getBlock('latest');
console.log('最新區塊包含的交易數:', block.transactions.length);
const tx = await web3.eth.getTransactionReceipt(block.transactions[0]);
console.log('交易 receipt:', tx);
})();第二種方案:輕量後端補足
若需「大量圖片」或「機器學習運算」,仍建議部署小型後端:
- 使用者先把資料上傳中心化服務。
- 後端回傳 IPFS hash,由前端將該 hash 寫進合約。
- 後端僅作快取,鏈上仍是真相來源;如此既降低成本,又保留 去中心化精神。
自動監聽事件(索引伺服器)
伺服器端透過 web3.eth.subscribe('logs') 監控事件:
contract.events.Transfer({
filter: { from: '0xTargetAddress' },
fromBlock: 'latest'
}, (err, event) => {
if (err) return console.error(err);
saveToLocalDB(event.returnValues);
});關鍵詞:索引伺服器、事件監聽、topics 篩選器、重組鏈檢查
一筆交易被「挖出」不等於最終確認,需等待 12 區塊(≈ 3 分鐘) 以防鏈重組。
第三種方案:批次任務(Cron Job)
- 使用 以太坊本地節點(Geth/Nethermind),每天自動結算。
- 先在線下簽章,再由後端將
rawTransaction廣播至 Infura 或自建節點。 - 避免私鑰暴露:將私鑰存入 環境變數 或硬體模組。
import Tx from 'ethereumjs-tx';
const tx = new Tx(txParams);
tx.sign(Buffer.from(PRIVATE_KEY, 'hex'));
const serialized = '0x' + tx.serialize().toString('hex');
web3.eth.sendSignedTransaction(serialized)
.on('receipt', r => console.log('已上鏈', r.transactionHash));常見問題 FAQ
Q1:前端錢包與 Infura 通訊不穩怎麼辦?
A:可於前端內建「後備 RPC 節點」陣列;當 Infura 逾時就自動切換至 Alchemy、自建節點或 Pocket Network,降低單點故障。
Q2:合約事件撈不到資料?
A:檢查 indexed 欄位。若事件 Transfer(address indexed from, address indexed to, uint value),from、to 會寫進 topics,其餘值存在 data,請分開解析。
Q3:重組鏈導致交易失效如何處理?
A:後台 API 須實作二次確認邏輯:交易初次回傳「接受」,等到鏈上區塊高度 >= tx.blockNumber + 12 再改狀態為「最終成功」。
Q4:大量圖片儲存成本太高?
A:採「鏈下儲存 + 鏈上證明」混合模式:圖片先存 IPFS,再在 NFT 合約內只保留 CID;若需防篡改,可在鏈下先算 Merkle Root 再上鏈。
Q5:測試網切換麻煩?
A:使用 chainId + hardhat.config.js 多網路開關 + 前端讀取 window.ethereum.chainId,可在 UI 提示用戶「請將網路切換至 Goerli」等。
Q6:如何估算 Gas?
A:呼叫 web3.eth.estimateGas({to, data, value}),再乘 1.1 安全係數;或使用 EIP-1559 時線上查 baseFee 並再加上優先費用(maxPriorityFeePerGas)。
結語:隨場景壘出最佳架構
沒有一種萬能公式可以套用所有 DApp 架構;小規模 NFT mint 可用無伺服器模式,鏈上胖、鏈下瘦;而需要 AI 推薦的 GameFi 便得中心化伺服器介入。靈活迭代、在不損去中心化核心精神的前提下,隨業務場景壘出自己的架構,才是「Web3 工程師」的終極修煉。
最後,記得不斷回頭檢視:「用戶真的需要鏈上執行這步驟嗎?」—— 只要反問三次,就能大幅壓低使用門檻與 gas 成本。祝你一鏈到底,專案早日落地。