使用 Node.js 服务器为 Next.js 授权 Azure 存储服务 REST API - 从 URL 复制 Blob

Posted

技术标签:

【中文标题】使用 Node.js 服务器为 Next.js 授权 Azure 存储服务 REST API - 从 URL 复制 Blob【英文标题】:Authorization of Azure Storage service REST API for Next.js with Node.js server - Copy Blob From URL 【发布时间】:2021-12-08 14:53:26 【问题描述】:

参考1:https://docs.microsoft.com/en-us/rest/api/storageservices/copy-blob-from-url

参考2:Authorization of Azure Storage service REST API

我根据上面的参考2实现了容器列表作为Next.js(/pages/api/)中的后端服务器。我在 Reference2 中实现了响应状态===OK。我的目标是使用 tier===cool 复制一个 blob,然后使用 tier===archive 将其粘贴到另一个容器中,这样我就不必在下载时更改存档 blob 的访问层。

我完全按照参考 2 进行了以下更改:

    将 strToSign 设置为(对此部分最不确定):

const strToSign= PUT\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:$strTime\nx-ms-version:2020-10-02\n/$account/\n$containerName/$blobName

    将标题(按照参考1)设置为:

     const putConfig = 
         method: 'PUT', 
         headers: 
             'Authorization': auth,
             'x-ms-date': strTime,
             'x-ms-version': "2020-10-02",
             'x-ms-copy-source': blobUrl,
             'x-ms-requires-sync':'true'
         
    

哪里(如参考文献1),

   const blobUrl = `https://$account.blob.core.windows.net/$containerName/$blobName`

    fetch 是这样设置的:

    fetch(https://$account.blob.core.windows.net/$containerName/$blobName, putConfig) .then( 结果 => console.log(results), res.end())

    这是我得到的 console.log(results) 输出:

    响应 大小:0, 超时:0, [符号(身体内部)]: 正文:直通 _可读状态:[可读状态], _events:[对象:空原型], _eventsCount:2, _maxListeners:未定义, _writableState:[可写状态], allowHalfOpen:真, [符号(kCapture)]:假, [符号(kCallback)]:空 , 不安:虚假, 错误:空 , [符号(响应内部)]: url: 'https://.blob.core.windows.net//', 状态:403, statusText: '服务器未能验证请求。确保 Authorization 标头的值正确形成,包括签名。', headers: Headers [Symbol(map)]: [Object: null prototype] , 计数器:0

不确定错误是什么 - 是否与在 azure 门户上的特定 blob(资源)上设置访问权限有关?你如何解决这个问题?

附言

参考3:Authentication Failed in REST api call to PUT Blob in Azure Storage [REST][Azure Blob]

我还尝试使用以下内容:

const strToSign = `PUT\n\n\n\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:$strTime\nx-ms-version:2020-10-02\n/$account/\n$containerName/\n$blobName`;

错误依旧。

【问题讨论】:

您不使用 SDK 有什么原因吗? 是的。我希望您在不更改其访问层的情况下下载存档的 Blob。如果 blob 位于存档层中,则不能将 blob 副本或来自 url 的 blob 副本与 sdk 一起使用。要重新水化存档的 blob,您需要使用 sdk 更改层,这意味着您会丢失存档的数据。如果您知道一种在不使用 sdk 更改其层的情况下复制 blob 的方法,请告诉我。欣赏! 简单的答案是你不能。为了读取存档的 blob,必须首先通过移动到热层或冷层来补充它。 【参考方案1】:

根据Gaurav Matri的建议

blob 位于归档访问层,它被认为处于离线状态,无法读取或修改。

为了读取或修改存档 blob 中的数据,您必须首先将该 blob 重新水化到在线层,无论是热层还是冷层

有两个选项可用于对存储在存档层中的 blob 进行再水化:

    将存档的 Blob 复制到在线层

您可以使用 Copy Blob 或 Copy Blob from URL 操作将已归档的 Blob 复制到热层或冷层中的新 Blob 来重新水化它。 Microsoft 建议在大多数情况下使用此选项。

    将 blob 的访问层更改为在线层

您可以通过使用Set Blob Tier 操作更改其层,将已归档的 blob 重新水化为热或冷。

更多详情请参考document

【讨论】:

首先,我想复制一个存档的 blob 以避免在更改层级时产生额外成本 - 这样就取消了选项 2。是的,我知道这个文档并且我阅读了它。我的理解是存档的 blob 只能通过 REST API 复制。但是,我给了 1) 一个机会:1) 我尝试了“syncCopyFromUrl”和“startCopyFromURL” 在这两种情况下,答案都是:“消息”:“在存档的 blob 上不允许此操作。”我使用的确切代码是这样的: const targetBlobClient = containerClient.getBlockBlobClient('targettest');等待 targetBlobClient.syncCopyFromURL(url); 因此,除非我对无法使用 SDK 复制存档 blob 有误(顺便说一句,如果您单击文档中的“复制 blob”和“从 url 复制 blob”链接,您将被转发到REST API 文档),我们回到最初的问题:我在原始电子邮件中的 REST API 代码有什么问题?【参考方案2】:

解决方案:

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

const key = "accesskey";
const version="2020-10-02"
const account = 'storagename'
const containerName = 'containername'
const strTime = (new Date()).toUTCString();

export default async (req, res) =>   
  if (req.method === 'POST') 

    const  blobName  = req.body
    const srcBlobName = blobName
    const srcBlobUrl = `https://$account.blob.core.windows.net/$containerName/$srcBlobName`
    const destBlobName = srcBlobName + 'rHrH'
    const destBlobUrl = `https://$account.blob.core.windows.net/$containerName/$destBlobName`;
    
    const destAccessTier = 'Cool'
    const canonicalizedHeaders = `x-ms-access-tier:$destAccessTier\nx-ms-copy-source:$srcBlobUrl\nx-ms-date:$strTime\nx-ms-version:$version\n`;
    const canonicalizedResource = `/$account/$containerName/$destBlobName`;
    const strToSign = `PUT\n\n\n\n\n\n\n\n\n\n\n\n$canonicalizedHeaders$canonicalizedResource`;
    const secret = CryptoJS.enc.Base64.parse(key);
    const hash = CryptoJS.HmacSHA256(strToSign, secret);
    const hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
    const auth = `SharedKey $account:`+hashInBase64;
    
    const PUTconfig = 
    method: 'PUT',
    headers: 
        'x-ms-access-tier': destAccessTier,
        'x-ms-copy-source': srcBlobUrl,
        'x-ms-date': strTime,
        'x-ms-version': version,
        'Authorization': auth
        
    ;

    fetch(destBlobUrl, PUTconfig)
    .then( results => 
        if(results.status==200) console.log('api works') else console.log(results),
        res.end()
    )    
   

【讨论】:

欢迎来到 Stack Overflow!请在您的代码中提供一些描述,以帮助读者理解您的解决方案。有关详细信息,请参阅How do I write a good answer?。 MSFT 在提示它不适合对 blob 进行再水化时删除了“从 blob url 复制”docs.microsoft.com/en-us/azure/storage/blobs/… 原因:无法设置目标 blob 的访问层

以上是关于使用 Node.js 服务器为 Next.js 授权 Azure 存储服务 REST API - 从 URL 复制 Blob的主要内容,如果未能解决你的问题,请参考以下文章

如何显示从 Node.js API 发送到 Next.js 的验证错误

无法在 Next.js 应用程序中使用 Apollo-client GraphQL 上传文件:缺少 POST 正文

Next.js 使用 JWT 进行身份验证

如何在同一个项目Node.js中将一个GAE服务列入另一个白名单

学不动了,Vercel 推出比 Vite 快 10 倍的打包器 Turbopack

学不动了,Vercel 推出比 Vite 快 10 倍的打包器 Turbopack