【问题标题】:API call to crypto.com in node returns invalid JSON response节点中对 crypto.com 的 API 调用返回无效的 JSON 响应
【发布时间】:2022-05-03 18:30:08
【问题描述】:

我正在使用 node-fetch 向 crypto.com 公共 API (reference) 发送 POST 请求。更具体地说,我正在尝试调用私有方法 get-account-summary,并且我正在使用我的 API 密钥和我的密钥在他们的 API 参考页面上预先签署请求(请参阅digital signature)。

const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));

fetch('https://api.crypto.com/v2/private/get-account-summary', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => response.body)
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

请求显然是成功的,但我很难理解应该看起来像这样的 API 响应:

{
    "id": 11,
    "method": "private/get-account-summary",
    "code": 0,
    "result": {
        "accounts": [
            {
                "balance": 99999999.905000000000000000,
                "available": 99999996.905000000000000000,
                "order": 3.000000000000000000,
                "stake": 0,
                "currency": "CRO"
            }
        ]
    }
}

但这是我实际得到的:

Success: PassThrough {
  _readableState: ReadableState {
    objectMode: false,
    highWaterMark: 16384,
    buffer: BufferList { head: null, tail: null, length: 0 },
    length: 0,
    pipes: [],
    flowing: null,
    ended: true,
    endEmitted: false,
    reading: false,
    constructed: true,
    sync: false,
    needReadable: false,
    emittedReadable: false,
    readableListening: false,
    resumeScheduled: false,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    destroyed: false,
    errored: null,
    closed: false,
    closeEmitted: false,
    defaultEncoding: 'utf8',
    awaitDrainWriters: null,
    multiAwaitDrain: false,
    readingMore: false,
    dataEmitted: false,
    decoder: null,
    encoding: null,
    [Symbol(kPaused)]: null
  },
  _events: [Object: null prototype] {
    prefinish: [Function: prefinish],
    error: [Function (anonymous)]
  },
  _eventsCount: 2,
  _maxListeners: undefined,
  _writableState: WritableState {
    objectMode: false,
    highWaterMark: 16384,
    finalCalled: true,
    needDrain: false,
    ending: true,
    ended: true,
    finished: true,
    destroyed: false,
    decodeStrings: true,
    defaultEncoding: 'utf8',
    length: 0,
    writing: false,
    corked: 0,
    sync: false,
    bufferProcessing: false,
    onwrite: [Function: bound onwrite],
    writecb: null,
    writelen: 0,
    afterWriteTickInfo: null,
    buffered: [],
    bufferedIndex: 0,
    allBuffers: true,
    allNoop: true,
    pendingcb: 0,
    constructed: true,
    prefinished: true,
    errorEmitted: false,
    emitClose: true,
    autoDestroy: true,
    errored: null,
    closed: false,
    closeEmitted: false,
    [Symbol(kOnFinished)]: []
  },
  allowHalfOpen: true,
  [Symbol(kCapture)]: false,
  [Symbol(kCallback)]: null
}

您可能已经注意到我将response.body 记录到控制台而不是response.json(),因为每当我调用后者时,我都会收到“无效的json 错误”

Error: FetchError: invalid json response body at
https://api.crypto.com/v2/private/get-account-summary reason:
Unexpected end of JSON input
    at C:\Users\...\app\node_modules\node-fetch\lib\index.js:273:32
    at processTicksAndRejections (node:internal/process/task_queues:96:5) {
  type: 'invalid-json' 

【问题讨论】:

  • “这是我实际得到的”——这不是有效的 JSON。
  • 我感觉这实际上不是 API 响应的内容,而是您的组件响应的内容。查看浏览器开发者工具上的网络选项卡并查看原始响应。
  • 哦,对了,node.js。你需要使用 Fiddler 或 Wireshark 或类似的东西。
  • 尝试记录 response.ok response.status response.headers.get('content-type') ...
  • @Aaronv 我添加了一个答案。我希望它对您的问题陈述有所帮助。

标签: javascript node.js json api


【解决方案1】:

许多 API 堆栈根据 2 个 Promise 工作:

  • 发出远程请求
  • 反序列化响应

根据docs,您需要等待.json() 调用。

import fetch from 'node-fetch';

const response = await fetch('https://httpbin.org/post', {
    method: 'post',
    body: JSON.stringify(body),
    headers: {'Content-Type': 'application/json'}
});
const data = await response.json();

使用 then 时,嵌套 promise 看起来更混乱,这就是为什么很多人更喜欢 async await 语法,但这会起作用:

request('https://api.crypto.com/v2/private/get-account-summary', {
  json: true,
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => {
   response.json()
       .then(data => {
            console.log(data);
        })
})

【讨论】:

  • 不幸的是,正如我在之前的评论中提到的(请参阅我的问题正下方的评论主题),使用 await fetch 会导致相同的错误:unexpected end of JSON input
【解决方案2】:

Fetch 返回一个响应流。更简单的方法是使用 npm request 包。

例如:

const request = require('request');
const requestBody = JSON.stringify(signRequest(request, apiKey, apiSecret));

request('https://api.crypto.com/v2/private/get-account-summary', {
  json: true,
  method: 'POST',
  headers: {'Content-Type': 'application/json'}, 
  body: requestBody
})
.then(response => response.body)
.then(data => {
  console.log('Success:', data);
})
.catch((error) => {
  console.error('Error:', error);
});

【讨论】:

    【解决方案3】:

    仅供参考,此问题与发出 API 请求的方式无关,而是与请求正文的签名有关(问题中未提及); signRequest(...) 方法在被字符串化后作为参数传递给fetch 方法,实际上并不返回任何值,而是改变请求参数。一旦我考虑到这一点,API 调用就成功了。

    【讨论】:

      【解决方案4】:

      编辑:对不起,我错过了问题的结尾。如果json() 无效并且text() 没有返回任何内容,我会说您应该检查您的请求正文。请求成功,但您得到一个空响应。

      不确定您为什么使用response.body。如果您想要 JSON 格式的响应,则需要使用 json()。这将获取正文并返回一个解析为请求格式的承诺。您可以阅读它here。

      所以,你的代码应该是这样的:

      fetch('https://api.crypto.com/v2/private/get-account-summary', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'}, 
        body: requestBody
      })
      .then(response => response.json())
      .then(data => {
        console.log('Success:', data);
      })
      .catch((error) => {
        console.error('Error:', error);
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-01-30
        • 1970-01-01
        • 2014-09-27
        • 2020-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多