0

我有一个 API,它为给定的 blob 名称生成并返回 SAS 令牌。然后在我的前端应用程序中,我使用 API 提供的响应(凭据)以及通过浏览器直接选择的文件来处理上传。

我正在使用blockBlobClient.uploadData函数。这工作正常并且上传成功完成,但是我注意到 SAS 令牌被重用于作为该 blob 的一部分上传和处理的所有块(我需要为 > 1GB 的文件做好准备),因此如果我的服务器返回一个 5 分钟的过期令牌,并且我的用户的连接速度很慢或部分中断,文件可能需要 5 分钟以上才能完成上传,这最终会从 Azure Blob API 向浏览器抛出错误,并且文件上传将停止。

我知道,一种方法当然是发行更长寿命的令牌来解决这些情况,或者可能根据文件大小设置过期时间;但我想知道是否有一种有效且不那么复杂的方式来以某种方式延长令牌的到期时间(不会丢失我当前对该 blob 的上传进度),以便即使达到第一个到期时间,文件也可以正确上传. 到目前为止还没有在文档中找到任何东西。

我将 NodeJs 用于我的后端 API,带有@azure/storage-blob npm 包(我也在我的前端应用程序中使用它)

希望这已经足够清楚了。

感谢您提供的任何帮助!

4

1 回答 1

0

解决方案 1: 注入新 SAS 以进行持续上传。有时 SAS 将在大型上传完成之前到期,对于这种情况,我们希望在上传期间请求新的 SAS 令牌,而不是开始新的上传。

尝试使用此代码更新 SAS 以上传大文件。

async function upload() {
  const sasStore = new SasStore();

  const pipeline = Azure.StorageURL.newPipeline(
    new Azure.AnonymousCredential()
  );
  // Inject SAS update policy factory into current pipeline
  pipeline.factories.unshift(new SasUpdatePolicyFactory(sasStore));

  const url = "https://jsv10.blob.core.windows.net/mycontainer/myblob";
  const blockBlobURL = new Azure.BlockBlobURL(
    `${url}${await sasStore.getValidSASForBlob(url)}`, // A SAS should start with "?"
    pipeline
  );

  const file = document.getElementById("file").files[0];
  await Azure.uploadBrowserDataToBlockBlob(
    Azure.Aborter.none,
    file,
    blockBlobURL,
    {
      maxSingleShotSize: 4 * 1024 * 1024
    }
  );
}
/ azblob is default exported entry when importing Azure Storage Blob SDK by <script src="azure-storage.blob.js"></script>
// You can also import SDK by npm package with const Azure = require("@azure/storage-blob")
const Azure = azblob;

// SasStore is a class to cache SAS for blobs
class SasStore {
  constructor() {
    this.sasCache = {};
  }

  // Get a valid SAS for blob
  async getValidSASForBlob(blobURL) {
    if (
      this.sasCache[blobURL] &&
      this.isSasStillValidInNext2Mins(this.sasCache[blobURL])
    ) {
      return this.sasCache[blobURL];
    } else {
      return (this.sasCache[blobURL] = await this.getNewSasForBlob(blobURL));
    }
  }


// Return true if "se" section in SAS is still valid in next 2 mins
  isSasStillValidInNext2Mins(sas) {
    const expiryStringInSas = new URL(`http://host${sas}`).searchParams.get(
      "se"
    );
    return new Date(expiryStringInSas) - new Date() >= 2 * 60 * 1000;
  }

  // Get a new SAS for blob, we assume a SAS starts with a "?"
  async getNewSasForBlob(blobURL) {
    // TODO: You need to implement this
    return "?newSAS";
  }
}

class SasUpdatePolicyFactory {
  constructor(sasStore) {
    this.sasStore = sasStore;
  }
  create(nextPolicy, options) {
    return new SasUpdatePolicy(nextPolicy, options, this.sasStore);
  }
}

class SasUpdatePolicy extends Azure.BaseRequestPolicy {
  constructor(nextPolicy, options, sasStore) {
    super(nextPolicy, options);
    this.sasStore = sasStore;
  }

  async sendRequest(request) {
    const urlObj = new URL(request.url);
    const sas = await this.sasStore.getValidSASForBlob(
      `${urlObj.origin}${urlObj.pathname}`
    );
    new URL(`http://hostname${sas}`).searchParams.forEach((value, key) => {
      urlObj.searchParams.set(key, value);
    });

    // Update request URL with latest SAS
    request.url = urlObj.toString();

    return this._nextPolicy.sendRequest(request);
  }
}

请按照此github代码了解更多详细信息。要创建新的 SAS,请参阅此线程

解决方案2: 不要上传大文件,而是分上传文件[方法将大文件拆分为更小的尺寸]。以块的形式上传文件,以便可以上传更大的文件而无需一次性完全读取它们。

更多详细信息请参阅此文档

于 2021-08-21T09:24:24.400 回答