在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储

Posted

技术标签:

【中文标题】在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储【英文标题】:Upload a Stream to Azure Blob Storage using REST API without Azure SDK 【发布时间】:2021-06-02 17:47:02 【问题描述】:

我希望以流的形式将文件上传到 Azure 存储,但我不想使用 Azure SDK,而是想以更通用的方式使用 REST API不是 BlobServiceClient

有没有办法做到这一点? 可以在此处找到相同的参考链接:

https://docs.microsoft.com/en-us/azure/storage/common/storage-samples-javascript?toc=/azure/storage/blobs/toc.json#blob-samples

https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/storage/storage-blob/samples/javascript/advanced.js#L74

但是这里提到的链接提出了一个使用Azure SDK 的解决方案。我想这样做 没有 Azure SDK

代码如下:

const CryptoJS = require("crypto-js");
const request = require("request");
const fs = require("fs");

const account = process.env.ACCOUNT_NAME || "";
const key = process.env.ACCOUNT_KEY || "";
const containerName = "demo";
const blobName = "dummyfile.txt";
var strTime = new Date().toUTCString();

// read file to Stream
var filePath = `$__dirname/README.md`;
const readStream = fs.createReadStream(filePath);
var stat = fs.statSync(filePath);

string_params = 
  verb: "PUT",
  "Content-Encoding": "",
  "Content-Language": "",
  "Content-Length": stat.size,
  "Content-MD5": "",
  "Content-Type": "application/octet-stream",
  Date: "",
  "If-Modified-Since": "",
  "If-Match": "",
  "If-None-Match": "",
  "If-Unmodified-Since": "",
  Range: "",
  CanonicalizedHeaders:
    "x-ms-blob-type:BlockBlob\nx-ms-date:" +
    strTime +
    "\nx-ms-version:" +
    "2020-04-08\n",
  CanonicalizedResource: `/$account/$containerName/$blobName`,
;

var strToSign = `$string_params["verb"]\n$string_params["Content-Encoding"]\n$string_params["Content-Language"]\n$string_params["Content-Length"]\n$string_params["Content-MD5"]\n$string_params["Content-Type"]\n$string_params["Date"]\n$string_params["If-Modified-Since"]\n$string_params["If-Match"]\n$string_params["If-None-Match"]\n$string_params["If-Unmodified-Since"]\n$string_params["Range"]\n$string_params["CanonicalizedHeaders"]$string_params["CanonicalizedResource"]`;

var secret = CryptoJS.enc.Base64.parse(key);
var hash = CryptoJS.HmacSHA256(strToSign, secret);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var auth = `SharedKey $account:` + hashInBase64;

const options = 
  url: `https://$account.blob.core.windows.net/$containerName/$blobName`,
  headers: 
    Authorization: auth,
    "x-ms-blob-type": "BlockBlob",
    "x-ms-date": strTime,
    "x-ms-version": "2020-04-08",
    "Content-Type": "application/octet-stream",
    "Content-Length": stat.size,
  ,
  body: readStream,
;

function callback(error, response, body) 
  console.log(response.statusCode);
  console.log(response.statusMessage);
  if (!error && response.statusCode == 200) 
    console.log(error);
    console.log(response);
    console.log(body);
  


request.put(options, callback);

我得到的错误是:

TypeError: Cannot read property 'statusCode' of undefined

编辑:问题已由 Pamela 的代码解决 + 我发现的问题是初始化 .env 变量时出错。

【问题讨论】:

【参考方案1】:

您可以使用Put Blob Rest API 上传流。有一个使用 node.js 的示例。

const CryptoJS = require("crypto-js");
const request = require("request");
const fs = require('fs');

const account = "account-name";
const key = "account-key";
var strTime = new Date().toUTCString();

var filePath = 'your-file-path';
const readStream = fs.createReadStream(filePath);
var stat = fs.statSync(filePath);

string_params = 
    'verb': 'PUT',
    'Content-Encoding': '',
    'Content-Language': '',
    'Content-Length': stat.size,
    'Content-MD5': '',
    'Content-Type': 'application/octet-stream',
    'Date': '',
    'If-Modified-Since': '',
    'If-Match': '',
    'If-None-Match': '',
    'If-Unmodified-Since': '',
    'Range': '',
    'CanonicalizedHeaders': 'x-ms-blob-type:BlockBlob\nx-ms-date:' + strTime + '\nx-ms-version:' + '2020-04-08\n',
    'CanonicalizedResource': `/$account/containername/myblob`



var strToSign = `$string_params['verb']\n$string_params['Content-Encoding']\n$string_params['Content-Language']\n$string_params['Content-Length']\n$string_params['Content-MD5']\n$string_params['Content-Type']\n$string_params['Date']\n$string_params['If-Modified-Since']\n$string_params['If-Match']\n$string_params['If-None-Match']\n$string_params['If-Unmodified-Since']\n$string_params['Range']\n$string_params['CanonicalizedHeaders']$string_params['CanonicalizedResource']`
console.log(strToSign);

var secret = CryptoJS.enc.Base64.parse(key);
var hash = CryptoJS.HmacSHA256(strToSign, secret);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var auth = `SharedKey $account:` + hashInBase64;
console.log(auth)

const options = 
    url: `https://$account.blob.core.windows.net/containername/myblob`,
    headers: 
        Authorization: auth,
        'x-ms-blob-type': 'BlockBlob',
        "x-ms-date": strTime,
        "x-ms-version": "2020-04-08",
        'Content-Type': "application/octet-stream",
        'Content-Length': stat.size
    ,
    body: readStream
;

function callback(error, response, body) 
    console.log(response.statusCode);
    console.log(response.statusMessage);
    if (!error && response.statusCode == 200) 
        console.log(error);
        console.log(response);
        console.log(body);
    


request.put(options, callback);

【讨论】:

您好 Pamela,我已经尝试过您提到的解决方案,但我正在寻找一种将数据作为流而不是直接作为整体上传的解决方案。还是谢谢你。 您的意思是将文件流上传到 azure blob? 是的,将 pdf、jpeg、JSON、文本文件作为数据流上传。 您可以将文件作为流读取,并将Content-Type设置为application/octet-stream 我尝试了你的意思,但仍然遇到问题,这是代码链接link。您能帮忙解决问题吗?【参考方案2】:

您可以尝试将 Azure REST API 用于 Blob 操作。你可以在这里找到 Blob 的 REST API - Operations on Blob

问题是您将如何在运行时处理流上传。 Azure SDK 支持流上传。但是,对于 REST API,您需要自己处理。

上传流或并行数据,您需要围绕此 REST API 调用进行一些包装以实现此目的

希望你觉得这很有用。

【讨论】:

嗨,Abhi,我不完全明白你的意思。这是代码link。你能看出问题出在哪里吗?

以上是关于在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储的主要内容,如果未能解决你的问题,请参考以下文章

如何在不更新 IOS 应用程序的情况下使用 Azure 通知中心

在不使用 PAT 的情况下验证 Azure Devops Api 调用?

在不使用主键或辅助键的情况下使用 azure 存储帐户进行身份验证

我们能否在不损害其他客户数据的情况下为不同客户使用单个 Azure 事件中心?

在不解决承诺的情况下使用 $http.post 和 res.redirect

如何在不使用库的情况下验证本机 Javascript 中的 Azure OAuth 访问 JWT 令牌?