在前端 DApp、链上套利、价格预警系统中,“如何将 ETH/USDT 价格、币安交易所某代币/USDT 价格实时拿到本地”是最常被问到的问题。本文手把手从 API 选择、代码构造到节点配置,帮你 10 分钟跑通示例程序,并一次性解答常见坑点。
1、两种数据源:链上 DEX 与中心化交易所
| 场景 | 数据源 | 方法 | 典型代表 |
|---|---|---|---|
| 链上价格 | 调用 DEX Router 合约 | getAmountsOut | Pancake、Uniswap V3 |
| 行情盘口 | 中心化交易所 REST/WS API | 公共接口签名 | 币安、OKX |
场景区别在于:
- DEX 价格 = 链上深度、无信任,但需节点和私钥签名交易;
- 币安数据 = 盘口挂单+成交量,更新到毫秒级,适合前端显示。
下文同时给出 web3.js 配合“DEX Router”与调用“币安行情接口”两段源码,你按需求自由组合。
2、准备工作
2.1 安装库
npm i web3 axios ethers2.2 免费 RPC
- BNB Chain:
https://bsc-dataseed.binance.org/ - 以太坊主网: 可用 infura、alchemy、Public Node
3、用 web3.js 读取 PancakeRouter 的 USDT 价格
步骤拆解
- 连接节点
- 生成 Router Contract 实例
- 指定 tokenIn、tokenOut、amountIn
- 调用
getAmountsOut得到 price
3.1 币安交易对:token/USDT
假设目标资产为 CAKE,合约地址:
CAKE = 0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82
USDT = 0x55d398326f99059fF775485246999027B3197955
router = 0x10ED43C718714eb63d5aA57B78B54704E256024E// price-token-usdt.js
const Web3 = require('web3');
const web3 = new Web3('https://bsc-dataseed.binance.org/');
const ROUTER_ABI = [{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"}];
const ROUTER_ADDR = '0x10ED43C718714eb63d5aA57B78B54704E256024E';
async function getTokenPriceUSDT(token, decimals = 18) {
const TOKEN_IN = token;
const TOKEN_OUT = '0x55d398326f99059fF775485246999027B3197955'; // USDT
const amountIn = web3.utils.toBN(10).pow(web3.utils.toBN(decimals));
const path = [TOKEN_IN, TOKEN_OUT];
const contract = new web3.eth.Contract(ROUTER_ABI, ROUTER_ADDR);
const [amountOut] = await contract.methods.getAmountsOut(amountIn, path).call();
return Number(amountOut) / 1e18;
}
getTokenPriceUSDT('0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82')
.then(p => console.log('1 CAKE ≈', p, 'USDT'))
.catch(console.error);3.2 ETH/USDT(以太坊主网版)
同理替换节点、Router、TOKEN_IN 即可:
// price-eth-usdt.js
const web3 = new Web3('https://mainnet.infura.io/v3/xxxxxxxx');
const USDT_ETH = '0xdAC17F958D2ee523a2206206994597C13D831ec7';
// UniswapV2 Router
const ROUTER_ETH = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D';
async function getETHPriceUSDT() {
const amountIn = web3.utils.toWei('1'); // 1 ETH
const path = [
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH
USDT_ETH
];
const router = new web3.eth.Contract(ROUTER_ABI, ROUTER_ETH);
const [,, out] = await router.methods.getAmountsOut(amountIn, path).call();
return Number(out) / 1e6;
}4、直接抓取 binance 汇率 API
若只希望在前端显示币安现货行情,无需链上交互。签名 Header 都省掉,这是最快的办法。
// binance-ticker.js
const axios = require('axios');
async function getBinanceTicker(symbol = 'ETHUSDT') {
const { data } = await axios
.get(`https://api.binance.com/api/v3/ticker/price?symbol=${symbol}`);
return Number(data.price);
}
getBinanceTicker('CAKEUSDT')
.then(p => console.log('Binance CAKE/USDT:', p));可同时将 CAKE、ETH、BTC、BNB 等推送到前端,用 Promise.all() 批量抓取。
5、常见进阶坑点
- 滑点过高:DEX 价格会因池子深度波动,大额兑换请使用 汇率预言机 如 Chainlink。
- 精度错乱:币安结果 6 位,BSC 代币常见 18 位,做除法前先看清
decimals。 - 节点延迟:公网 RPC 高峰期 2–4 秒,可在项目里做缓存 3–5 秒。
6、FAQ:5 个你一定会用到的问题
Q1:只用 web3.js 能否调用 Binance 行情?
A:不能。web3.js 只针对链上智能合约。Binance 数据源自中心服务器,需走 REST/WS。
Q2:getAmountsOut 得到的只是“理论价”,会随时变吗?
A:会变,任何人下一笔交易都会把价格推倒新平衡。如需保险,先用 reserves() 读池子深度,再去估算滑点。
Q3:如何避免前端被限速?
A:三个技巧:
a. 前端缓存 LocalStorage/IndexedDB 5 秒;
b. 用 Vercel Function / Cloudflare Workers 做一层代理解决 CORS;
c. 签专用 API-KEY 额外请求额度。
Q4:直接用 Chainlink 价格 feed 是不是更省心?
A:Chainlink Feed 延迟 1~10 分钟,单节点报错也无法自动熔断。适合结算场景;交易撮合仍建议实时读 Router。
Q5:本地测试链没有流动性怎么办?
A:Hardhat Fork BSC/ETH 主网。默认 2,000 区块深度,足够大多数模拟需求。
最后别忘了:把 Router 版本、数据源切换、精度处理放进统一配置文件,后期上新链就像拼积木一样简单。现在动手改两行代码,你就拥有全功能 实时链上加中心化行情看板!