如何用Google Apps Script调用Bybit API?遇403错误求解决
Google Apps Script调用Bybit API遇403错误(Node.js可正常运行)
我用Node.js调用Bybit API能正常拿到响应,但转成Google Apps Script(GAS)代码后却出现奇怪的403错误。试过各种写法,查了一堆文档,参考了别人的API实现,代码逻辑上没问题就是跑不通,现在卡壳了。
当前GAS代码(已替换密钥)
var apiKey = 'XXXXX'; var timestamp = new Date().getTime().toString(); var recvWindow = '5000'; var parameters = 'accountType=SPOT'; var message = timestamp + apiKey + recvWindow + parameters; var url = 'https://api.bybit.com/v5/asset/transfer/query-account-coins-balance?accountType=SPOT'; const secret = 'XXXXXXXXXXXX'; function createSign() { var signatureBytes = Utilities.computeHmacSha256Signature(message, secret); var signature = signatureBytes.reduce(function(str, byte) { return str + ('0' + (byte & 0xFF).toString(16)).slice(-2); }, ''); Logger.log(signature); return signature.toString(); } function main() { var config = { method: 'GET', headers: { 'X-BAPI-API-KEY': apiKey, 'X-BAPI-TIMESTAMP': timestamp, 'X-BAPI-RECV-WINDOW': recvWindow, 'X-BAPI-SIGN': createSign() }, muteHttpExceptions: true } var response = UrlFetchApp.fetch(url, config); var response2 = UrlFetchApp.getRequest(url, config); Logger.log(response2); Logger.log(response); }
返回的403错误信息
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> <TITLE>ERROR: The request could not be satisfied</TITLE> </HEAD><BODY> <H1>403 ERROR</H1> <H2>The request could not be satisfied.</H2> <HR noshade size="1px"> The Amazon CloudFront distribution is configured to block access from your country. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner. <BR clear="all"> If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation. <BR clear="all"> <HR noshade size="1px"> <PRE> Generated by cloudfront (CloudFront) Request ID: ns9XoZU762a7V7mCAE07rgmK3dWkOtjKK9LHuyNjyTW14CQkdvUGtw== </PRE> <ADDRESS> </ADDRESS> </BODY></HTML>
可正常运行的Node.js代码
const axios = require('axios'); const crypto = require('crypto'); const apiKey = 'XXXXXXX'; const timestamp = Date.now().toString(); const recvWindow = '5000'; const secret = 'XXXXXXXXX' function sign(parameters, secret) { const signature = crypto.createHmac('sha256', secret).update(timestamp + apiKey + recvWindow + parameters).digest('hex'); console.log(signature); return signature.toString(); } async function main() { const config = { method: 'get', url: 'https://api.bybit.com/v5/asset/transfer/query-account-coins-balance?accountType=SPOT', headers: { 'X-BAPI-API-KEY': apiKey, 'X-BAPI-TIMESTAMP': timestamp, 'X-BAPI-RECV-WINDOW': recvWindow, 'X-BAPI-SIGN': sign('accountType=SPOT', secret) } }; await axios(config) .then((response) => { console.log(response.data.result); }) .catch((error) => { console.log(error); }); console.log(sign('accountType=SPOT', secret).length); } main();
解决思路与修复方案
从错误信息看,CloudFront提示“你的国家被屏蔽”,但Node.js能正常访问,说明问题不在你的物理位置,而是GAS请求的来源IP(Google云服务器IP)被Bybit的CloudFront规则拦截了,或者请求头不符合要求。
1. 修正时间戳与签名的生成时机
原GAS代码中timestamp和message是全局初始化的,当main函数执行时,时间可能已经过期(Bybit要求时间戳与服务器时间差不超过recvWindow)。把这些变量移到main内部,确保签名用的时间戳和请求头完全一致。
2. 添加标准User-Agent头
GAS默认的请求头可能被识别为异常客户端,添加常见浏览器的User-Agent可以降低被拦截的概率。
修复后的完整GAS代码
var apiKey = 'XXXXX'; const secret = 'XXXXXXXXXXXX'; var recvWindow = '5000'; function createSign(message, secret) { var signatureBytes = Utilities.computeHmacSha256Signature(message, secret); var signature = signatureBytes.reduce(function(str, byte) { return str + ('0' + (byte & 0xFF).toString(16)).slice(-2); }, ''); Logger.log(signature); return signature; } function main() { // 确保时间戳在请求生成时才获取 var timestamp = new Date().getTime().toString(); var parameters = 'accountType=SPOT'; var message = timestamp + apiKey + recvWindow + parameters; var url = 'https://api.bybit.com/v5/asset/transfer/query-account-coins-balance?accountType=SPOT'; var config = { method: 'GET', headers: { 'X-BAPI-API-KEY': apiKey, 'X-BAPI-TIMESTAMP': timestamp, 'X-BAPI-RECV-WINDOW': recvWindow, 'X-BAPI-SIGN': createSign(message, secret), // 添加标准User-Agent 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' }, muteHttpExceptions: true }; var response = UrlFetchApp.fetch(url, config); Logger.log(response.getContentText()); }
3. 备选方案:使用代理转发请求
如果上述方法无效,可以尝试通过支持HTTPS的代理服务器转发GAS的请求,绕过CloudFront的IP拦截。
内容的提问来源于stack exchange,提问作者marremarräng
相关产品推荐
相关产品推荐

