You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Coinbase Send Money API返回Cloudflare 400错误(Go实现)

Coinbase Send Money API请求返回Cloudflare 400错误求助

调用Coinbase的Send Money API端点时,请求返回HTML格式的Cloudflare 400错误,而非官方文档中说明的标准JSON错误响应。具体响应内容如下:

<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

已完成以下排查操作:

  • 切换不同地区VPN无效,未发现请求头存在异常信息;
  • 移除API密钥/秘钥请求头后,可正常返回未认证的JSON格式错误;
  • 其他GET类型的API端点能够正常调用;
  • 确认API密钥已包含wallet:transactions:send权限;
  • 使用主账户和指定账户ID发起请求,均出现相同错误;
  • 修改POST请求payload字段顺序(匹配文档或按字母排序),问题依旧存在。

相关Go语言请求代码如下:

var (
    cbAPIKey    = os.Getenv("CB_API_KEY")
    cbAPISecret = os.Getenv("CB_API_SECRET")
    ethAccountID = os.Getenv("CB_ETH_ACCOUNT_ID")

    version = "2023-04-01" // https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/versioning
)

func TestSendEth(t *testing.T) {
    destination := "..."
    transaction, err := SendEth(destination, "0.1")
    assert.Nil(t, err)
    assert.Equal(t, destination, transaction.To.Address)
}

type sendPayload struct {
    Type        string  `json:"type"` // must be "send"
    To          string  `json:"to"`
    Amount      string  `json:"amount"`
    Currency    string  `json:"currency"`
    Description *string `json:"description,omitempty"`
    Idem        *string `json:"idem,omitempty"`
    // For select currencies, destination_tag or memo indicates the beneficiary or destination of a
    // payment for select currencies. Example:
    // { "type" : "send", "to": "address", "destination_tag" : "memo", "amount": "", "currency": "" }
    DestinationTag *string `json:"destination_tag,omitempty"`
}

func SendEth(to, amount string) (transaction Transaction, err error) {
    payload := sendPayload{
        Type:     "send",
        To:       to,
        Amount:   amount,
        Currency: "ETH",
    }

    // serialize payload
    b, _ := json.Marshal(payload)
    reader := bytes.NewReader(b)

    url := fmt.Sprintf(transactionsURL, ethAccountID)
    req, _ := http.NewRequest("POST", url, reader)
    req.Header.Set("Content-Type", "application/json")

    // sign request
    err = signRequest(req)
    if err != nil {
        return
    }

    // send request
    c := http.Client{}
    response, err := c.Do(req)
    if err != nil {
        return
    }

    var cbResponse Response[Transaction]
    responseBytes, _ := ioutil.ReadAll(response.Body)
    err = json.Unmarshal(responseBytes, &cbResponse)
    if err != nil {
        log.Warn(string(responseBytes))
        log.WithError(err).Error("Failed to unmarshal response")
        return
    }

    transaction = cbResponse.Data
    return
}

// signRequest modifies a http.Request to include the Coinbase-Auth-Signature
// headers. You can find more information about these headers here:
// https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
func signRequest(req *http.Request) (err error) {
    reqTime := time.Now().Unix()

    /*
        The CB-ACCESS-SIGN header is generated by creating a sha256 HMAC using the secret key on the
        prehash string timestamp + method + requestPath + body (where + represents string concatenation).

        timestamp is the same as the X-CB-ACCESS-TIMESTAMP header.
        method should be UPPER CASE.
        requestPath is the full path and query parameters of the URL, e.g.: /v2/exchange-rates?currency=USD.
    */
    body := ""

    if req.Body != nil {
        var bytes []byte
        bytes, err = ioutil.ReadAll(req.Body)
        if err != nil {
            return
        }
        body = string(bytes)
    }

    message := fmt.Sprintf("%d%s%s%s", reqTime, req.Method, req.URL.Path, body)

    // generate a sha256 HMAC using the secret key on the prehash string
    signature := generateHMAC(message, cbAPISecret)

    req.Header.Set("CB-ACCESS-KEY", cbAPIKey)
    req.Header.Set("CB-ACCESS-SIGN", signature)
    req.Header.Set("CB-ACCESS-TIMESTAMP", fmt.Sprintf("%d", reqTime))
    req.Header.Set("CB-VERSION", version)

    return
}

原本预期操作有误时能收到明确的错误提示,但现在仅得到模糊的Cloudflare错误,实在找不到问题所在,恳请帮忙排查!

内容的提问来源于stack exchange,提问作者adk992

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 19:24:57