PHP Laravel调用Bitunix API报10007签名错误求助
Bitunix API修改保证金模式时10007签名错误排查与解决
我尝试用PHP对接Bitunix API修改保证金模式,严格按照官方文档实现,但始终遇到10007签名错误,多次调整代码仍无法解决。希望有人帮忙分析错误原因,并提供正确的API对接示例或思路。
我的代码
API类代码
<?php namespace App\Classes\Api; use GuzzleHttp\Client; class BitunixFuturesApi{ public string $base_url = "https://fapi.bitunix.com/"; public string $klineE = "api/v1/futures/market/kline"; public string $marginModeE = "api/v1/futures/account/change_margin_mode"; public string $apiKey = "random"; public string $secretKey = "random"; public function set_margin_mode($symbol="BTCUSDT", $marginMode = "ISOLATED", $marginCoin = "USDT"):array{ try{ $client = new Client(); $params = [ "marginMode" => $marginMode, "symbol" => $symbol, "marginCoin" => $marginCoin ]; $apiKey = $this->apiKey; $secretKey = $this->secretKey; $nonce = bin2hex(random_bytes(16)); $queryParamsString = ''; ksort($params); foreach ($params as $key => $value) { $queryParamsString .= $key . $value; } $body = json_encode($params); $timestamp = (int)(microtime(true)*1000); $digest = hash('sha256' , $nonce.$timestamp.$apiKey.$queryParamsString.$body); $sign = hash('sha256', $digest.$secretKey); $response = $client->post($this->base_url.$this->marginModeE,[ 'headers'=>[ 'api-key' => $apiKey, 'sign' =>$sign, 'timestamp' => $timestamp, 'nonce'=>$nonce, 'Content-Type'=> 'application/json' ], 'json'=>$params ]); $response = json_decode($response->getBody()->getContents(),false,512,JSON_THROW_ON_ERROR); if($response->code ==0){ return ['success'=>true, 'message'=>"Margin mode changed successfully", 'data' => $response->data]; } return ['success'=>false, 'message'=>"Error changing margin mode", 'data' => $response->msg, 'code'=>$response->code]; }catch(\Exception $e){ return ['success'=>false, 'message'=>$e->getMessage(),'line'=>$e->getLine(),'file'=>$e->getFile(), 'data' => '']; } } }
控制器代码
<?php namespace App\Http\Controllers\Dashboard; use App\Classes\Api\BitunixFuturesApi; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class TradeController extends Controller { public function __construct(){ $this->middleware('auth'); } public function index(){ $bit = new BitunixFuturesApi(); $data = $bit->set_margin_mode("BTCUSDT", "CROSS"); return view('dashboard.trade')->with('data',$data); } }
错误截图

错误原因分析与修正方案
核心错误点
- query参数拼接错误:原代码将POST请求的body参数当作URL的query参数进行拼接,但该接口为POST请求,URL无query参数,这直接导致签名原始字符串与官方要求不符。
- 请求体一致性问题:使用Guzzle的
'json' => $params会自动编码JSON,可能与手动json_encode($params)的结果存在格式差异(如空格、编码方式),导致签名时的body字符串与实际发送的不一致。 - nonce格式可能不符合要求:部分API要求nonce为数字类型,原代码生成的是十六进制字符串,可能不被服务端认可。
修正后的API类代码
<?php namespace App\Classes\Api; use GuzzleHttp\Client; class BitunixFuturesApi{ public string $base_url = "https://fapi.bitunix.com/"; public string $klineE = "api/v1/futures/market/kline"; public string $marginModeE = "api/v1/futures/account/change_margin_mode"; public string $apiKey = "你的API密钥"; public string $secretKey = "你的Secret密钥"; public function set_margin_mode($symbol="BTCUSDT", $marginMode = "ISOLATED", $marginCoin = "USDT"):array{ try{ $client = new Client(); $params = [ "marginMode" => $marginMode, "symbol" => $symbol, "marginCoin" => $marginCoin ]; // 按key升序排序body参数(官方要求body参数需排序后生成JSON) ksort($params); $apiKey = $this->apiKey; $secretKey = $this->secretKey; // 生成数字类型nonce:毫秒时间戳+随机数,确保唯一性且符合多数API规范 $nonce = (string)(microtime(true)*1000) . rand(1000, 9999); $timestamp = (int)(microtime(true)*1000); // POST请求无URL query参数,因此queryParamsString为空 $queryParamsString = ''; // 生成与实际发送完全一致的JSON字符串 $body = json_encode($params, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); // 严格按照官方顺序构造签名原始字符串 $rawString = $nonce . $timestamp . $apiKey . $queryParamsString . $body; $digest = hash('sha256', $rawString); $sign = hash('sha256', $digest . $secretKey); $response = $client->post($this->base_url . $this->marginModeE, [ 'headers' => [ 'api-key' => $apiKey, 'sign' => $sign, 'timestamp' => $timestamp, 'nonce' => $nonce, 'Content-Type' => 'application/json' ], // 直接使用预先生成的body字符串,确保与签名时的内容一致 'body' => $body ]); $responseData = json_decode($response->getBody()->getContents(), false, 512, JSON_THROW_ON_ERROR); if($responseData->code == 0){ return ['success'=>true, 'message'=>"保证金模式修改成功", 'data' => $responseData->data]; } return ['success'=>false, 'message'=>"修改保证金模式失败", 'data' => $responseData->msg, 'code'=>$responseData->code]; }catch(\Exception $e){ return ['success'=>false, 'message'=>$e->getMessage(),'line'=>$e->getLine(),'file'=>$e->getFile(), 'data' => '']; } } }
关键调整说明
- 移除了错误的body参数到query参数的拼接逻辑,明确
queryParamsString为空(因该接口无URL query参数)。 - 改用
'body' => $body替代Guzzle的'json'选项,确保发送的JSON字符串与签名时使用的完全一致。 - 调整nonce生成方式为数字字符串,避免格式不兼容问题。
- 对body参数执行升序排序后再生成JSON,符合官方对POST请求body参数的排序要求。
内容的提问来源于stack exchange,提问作者MohsenCreative




