如何在JavaScript中使用access ID和secret key调用CoinEx API解决签名错误
错误原因
- 签名计算逻辑不符合规则:CoinEx API的签名不是直接对SecretKey做MD5,需要按指定规则拼接参数后再加密
- SecretKey违规传输:SecretKey属于敏感信息,仅可用于本地签名计算,不能放在请求URL、请求头或请求体中传输
- tonce参数格式错误:从行情接口获取的时间为秒级时间戳,CoinEx要求tonce为毫秒级整数,且和服务器时间误差不能超过30秒
- 参数未按要求排序:签名前需要将所有请求参数按key的ASCII码升序排列后再拼接
签名计算正确流程
- 收集当前接口所有请求参数(余额查询接口仅需要
access_id、tonce两个参数) - 将参数按照key的ASCII码从小到大排序
- 把排序后的参数拼接为
key=value格式,用&连接成字符串 - 在拼接好的字符串末尾追加
&secret_key=你的SecretKey - 对最终字符串做MD5加密,结果转为全大写,即为请求头需要的authorization值
修复后完整代码
<html> <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script> <script> const AccessID = "61CFB9AB7F0B46B18F26EE2E3F155F4C"; const SecretKey = "109E2A9E37DD4257D4C6DEDFE3F261A269EEB98DAA48B3E1"; Process(); async function Process() { // 获取服务器时间校正本地时间差 const marketRes = await fetch("https://api.coinex.com/v1/market/ticker/all"); const marketJson = await marketRes.json(); const serverTimeSec = parseInt(marketJson.data.date); // 转成毫秒级tonce const tonce = serverTimeSec * 1000; // 构造请求参数 const params = { access_id: AccessID, tonce: tonce }; // 按ASCII排序参数key const sortedKeys = Object.keys(params).sort(); // 拼接参数 let paramStr = sortedKeys.map(key => `${key}=${params[key]}`).join('&'); // 拼接secret_key paramStr += `&secret_key=${SecretKey}`; // 计算签名 转大写 const signature = CryptoJS.MD5(paramStr).toString().toUpperCase(); // 发起请求 const accountRes = await fetch(`https://api.coinex.com/v1/balance/info?${new URLSearchParams(params)}`, { method: "get", headers: { "authorization": signature } }); const accountJson = await accountRes.json(); console.log(accountJson); alert(accountJson.message); } </script> </html>
注意事项
- 实际生产环境中不要将SecretKey写在前端代码中,会导致资产被盗,前端仅适合做公开接口调用,私有接口请放在后端服务请求
- 本地时间如果准确可以直接用
Date.now()作为tonce,不需要每次请求行情接口拿时间
内容的提问来源于stack exchange,提问作者Programmer
相关产品推荐
相关产品推荐

