node.js - Azure Blob 服务 REST API - 错误 : read ECONNRESET

标签 node.js azure http azure-blob-storage

目标以及我目前取得的进展

我正在尝试将 Azurue 存储 Blob 服务 REST API 与 Node.JS 结合使用。到目前为止,我成功地请求了 List ContainersGet Blob Services Properties 操作。现在我正在尝试基于 this documentationPut Blob来自微软。

我遇到过 400 和 403 错误,并搜索过类似的问题,即使它是 a question on C#on R阅读它而不是 Node.JS,可以帮助我了解我可能做错了什么并更改我的代码。在这种情况下,签名及其规范化资源和规范化 header 缺乏更清晰的文档。

问题

当我以为我解决了签名问题(毕竟响应不再告诉我这就是问题所在)并且现在我不再有这些错误时,所发生的一切是:我发出请求,它卡住了一段时间尽管;一段时间后我收到消息:

events.js:292
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TLSWrap.onStreamRead (internal/stream_base_commons.js:205:27)
Emitted 'error' event on ClientRequest instance at:
    at TLSSocket.socketErrorListener (_http_client.js:426:9)
    at TLSSocket.emit (events.js:315:20)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at processTicksAndRejections (internal/process/task_queues.js:84:21) {
  errno: 'ECONNRESET',
  code: 'ECONNRESET',
  syscall: 'read'
}

来自this question on a similar issue我了解到这是 TCP 另一端的连接中断。所以它可能不再是签名了,但我不知道它是什么。我是否需要在 Put Blob 之前发出其他类型的请求?

我尝试更改签名,还尝试创建要上传的本地 .txt 文件,并尝试从变量上传简单的字符串。 我不确定数据应该从哪里上传。

我认为我的主要问题是,对于我遇到的其他错误和问题,我得到了一些信息来(最终在大量阅读之后)解决它;但现在我什至不再获得 Status 200。

代码

我的创建签名的函数:

/**
   * Authorization using HMAC SHA 256.
   * @param {String} VERB - Request method to be used (GET, PUT).
   * @param {String} strTime - Time of the request, in RFC 1123 Format.
   * @param {String} path - Path of the URL, containing the name of the
   * container and the query parameters.
   */
  create_signature(VERB, strTime, uri, content) {
    VERB = VERB.toUpperCase();

    // removing first slash
    uri = uri.replace("/","");
    
    // separating '/container/blob?q=query&q=query' into 'container/blob' and 'q=query&q=query'
    var [path, query] = uri.split("?");
    // changing 'q=query&q=query' to 'q:query\nq:query' if '?' is included
    query = query ? query.replace(/\=/g,":").replace(/\&/g,"\n") : '';
    // without the '?' char the separation is '/container/blob' and ''
    
    const content_type = "text/plain; charset=UTF-8";
    const content_length = content.length.toString();
    
    let strToSign = VERB + "\n" + // VERB
      "\n" +                      // Content-Encoding
      "\n" +                      // Content-Language
      content_length + "\n" +     // Content-Length
      "\n" +                      // Content-MD5
      content_type + "\n" +         // Content-Type
      "\n" +                      // Date
      "\n" +                      // If-Modified-Since
      "\n" +                      // If-Match
      "\n" +                      // If-None-Match
      "\n" +                      // If-Unmodified-Since
      "\n" +                      // Range
      // CanonicalizedHeaders
      `x-ms-blob-type:BlockBlob` + "\n" +
      `x-ms-date:${strTime}` + "\n" + 
      `x-ms-version:${this.version}` + "\n" +
      // CanonicalizedResource
      `/${this.account_name}/${path}`;

    console.log(strToSign);
    // strToSign = strToSign.toLowerCase();
    // strToSign = encodeURIComponent(strToSign);

    // generating secret from account key
    var secret = CryptoJS.enc.Base64.parse(this.account_key);
    // encrypting the signature
    var hash = CryptoJS.HmacSHA256(strToSign, secret);
    var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
    var auth_sig = `SharedKey ${this.account_name}:` + hashInBase64;

    return auth_sig;
  }

使用 http 模块发出请求:

// making the request using the http module:
  put_blob(container_name, filename) {
    const time_UTC_str = new Date().toUTCString();
    var path = `/${container_name}/${filename}`;

    const obj = "hello world";

    const signature = this.create_signature('PUT', time_UTC_str, path, obj);


    const req_params = {
      method: 'PUT',
      hostname: this.hostname,
      path: path,
      headers: {
        'Authorization': signature,
        'x-ms-date': time_UTC_str,
        'x-ms-version': this.version,
        'x-ms-blob-type': 'BlockBlob',
        'Content-Length': obj.length.toString(),
        'Content-Type': "text/plain; charset=UTF-8"
      }
    }

    let req = http.request(req_params, this.res_handler);
    req.end();
  }

响应处理函数:

  /**
 * Callback function that handles and parses the responses, 
 * including how the search results will be processed.
 * @param {object} res - response from request
 */
  res_handler = function (res) {

    let body = '';
    // storing body
    res.on('data', (dat) => {
      body += dat;
    });

    // when signaling 'end' flag
    res.on('end', () => {
      // parsing response
      if (!res.complete) {
        console.error('The connection was terminated while the message was still being sent');
      } else {
        // console.log(res);
        console.log(`Status: ${res.statusCode} - ${res.statusMessage}`);
      }
      console.log('Response: ' + body);
      
    });

    // handling errors
    res.on('error', (err) => {
      console.error(`Error ${err.statusCode}: ${err.statusMessage}`);
    });

  };

PS: Should I try another cloud service or are they all complicated and bad documented?

最佳答案

我忘记使用req.write()来实际写入数据。我很尴尬,但我会解释发生了什么,以防有人遇到类似的问题。

正如我之前所解释的,该错误来自另一端的连接中断,例如不活动超时。所以它一直等待我向请求写入数据,因为我没有写入数据,所以它最终停止等待,从而返回该错误。

事实证明,它与 Azure 或 Blob 服务无关,我只是没有发送任何要上传的内容。我花了一些时间才意识到这一点,但在这个过程中,我通过研究这一点确实学到了很多东西。

put_blob() 方法的最后几行现在如下所示:

let req = http.request(req_params, this.res_handler);
req.write(obj);    // it was missing this! 
req.end();

现在我(希望)永远不会忘记在 PUT 请求上写入数据。

关于node.js - Azure Blob 服务 REST API - 错误 : read ECONNRESET,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66171580/

相关文章:

node.js - 如何修复请求错误: Error: connect ETIMEDOUT while running Mocha JS/NodeJS test from behind proxy

javascript - 如何在 Node.js 中 trim JSON 输出中的空格?

node.js - node.js 是否已准备好用于中型/大型企业 Web 应用程序?

java - 使用 Java 进行编码的 Azure 功能应用程序

azure - 无法通过 helm 访问 AKS 上的 Kubernetes LoadBalancer 服务

Angularjs $http缓存刷新

json - 如果 REST API 返回 JSON,那么 MIME 类型是什么?

javascript - XMLHttpRequest 分块响应,只读取正在进行的最后一个响应

azure - 在 Azure 管道中,如何设置 X 显示以进行 headless (headless) Chrome 测试?

qt - 如何使用 Qt 从 SourceForge 下载文件