You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

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);
    }
}

错误截图

错误截图


错误原因分析与修正方案

核心错误点

  1. query参数拼接错误:原代码将POST请求的body参数当作URL的query参数进行拼接,但该接口为POST请求,URL无query参数,这直接导致签名原始字符串与官方要求不符。
  2. 请求体一致性问题:使用Guzzle的'json' => $params会自动编码JSON,可能与手动json_encode($params)的结果存在格式差异(如空格、编码方式),导致签名时的body字符串与实际发送的不一致。
  3. 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

火山引擎 最新活动