简体   繁体   中英

Upload large file to Azure blob storage via REST API Put Block Blob

I am using React Native to build Mobile application for Andrioid and iOS.

based on the situation that no framework is exist to support Azure Storage API for React Native (all frameworks are required browsers that does not exist in React Native),

I use REST API for the interaction with the Azure storage and it works fine eg list containers, list blob, get blob and put blob.

in order to upload large file I tried to use the same mechanizm for 'put block' api (as describe here: https://learn.microsoft.com/en-us/rest/api/storageservices/put-block ) without succcess, failed on error code 403.

I will appreciate for your assist.

Thank you.

my code for upload single block:

private createAuthorizationHeader(canonicalizedString: string) {
  const str = CryptoJS.HmacSHA256(canonicalizedString, CryptoJS.enc.Base64.parse(this.config.accountKey));
  const sig = CryptoJS.enc.Base64.stringify(str);
  const authorizationHeader = `SharedKey ${this.config.accountName}:${sig}`;
  return authorizationHeader;
}
  

  
async putBlockBlob(containerName: str, blobPath: str, blobContent: str, blockIndex: number,) {
  const requestMethod = 'PUT';
    
  const urlPath = `${containerName}/${blobPath}`;
    
  const dateInRfc1123Format = new Date(Date.now()).toUTCString();
    
     const storageServiceVersion = '2019-12-12';
    
     const blobLength: number = blobContent.length;
    
     const blockId = Buffer.from(`block-${blockIndex}`).toString('base64');
    
     const blobType = 'BlockBlob';
    
     // StringToSign =
     //   VERB + "\n" +
     //   Content-Encoding + "\n" +
     //   Content-Language + "\n" +
     //   Content-Length + "\n" +
     //   Content-MD5 + "\n" +
     //   Content-Type + "\n" +
     //   Date + "\n" +
     //   If-Modified-Since + "\n" +
     //   If-Match + "\n" +
     //   If-None-Match + "\n" +
     //   If-Unmodified-Since + "\n" +
     //   Range + "\n" +
     //   CanonicalizedHeaders +
     //   CanonicalizedResource;
    
     const canonicalizedHeaders = `x-ms-date:${dateInRfc1123Format}\nx-ms-version:${storageServiceVersion}`;
     const canonicalizedResource = `/${this.config.accountName}/${urlPath}}\nblockid:${blockId}\ncomp:block`;
    
     const stringToSign = `${requestMethod}\n\n\n${blobLength}\n\napplication/octet-stream\n\n\n\n\n\n\n${canonicalizedHeaders}\n${canonicalizedResource}`;
    
     const uriStr = `${urlPath}?comp=block&blockid=${blockId}`;
    
     const authorizationHeader = this.createAuthorizationHeader(stringToSign);
    
     const header = {
       'cache-control': 'no-cache',
       'x-ms-date': dateInRfc1123Format,
       'x-ms-version': storageServiceVersion,
       Authorization: authorizationHeader,
       'Content-Length': `${blobLength}`,
       'Content-Type': 'application/octet-stream',
     };
    
    
     try {
       return axios
         .create({baseURL: `https://${this.config.accountName}.blob.core.windows.net/`,})
         .request({
           method: requestMethod,
           url: uriStr,
           data: blobContent,
           headers: header,
         })
         .then((response) => response.data)
         .catch((err) => {
           throw err;
         });
     } catch (err) {
       console.log(err);
       throw err;
     }
   }

I believe the issue is coming because of a missing new line character between Range and CanonicalizedHeaders .

Can you try by changing the following line of code:

const stringToSign = `${requestMethod}\n\n\n${blobLength}\n\napplication/octet-stream\n\n\n\n\n\n\n${canonicalizedHeaders}\n${canonicalizedResource}`;

to:

const stringToSign = `${requestMethod}\n\n\n${blobLength}\n\napplication/octet-stream\n\n\n\n\n\n\n\n${canonicalizedHeaders}\n${canonicalizedResource}`;

it will help you to upload the data to Azure storage server

upload file to Server

export const uploadMedia = async (params: any, callBack: any) => {
  const SAS_URL: any = "https://${blobUrl}.blob.core.windows.net";
  const CONTAINER: any = "";
  const SAS_TOKEN: any = "";

  const { fileType, localUri } = params;
  const userId = "set user ID here";
  const fileName = String(fileType).concat(customIdGenerator(7));
  const assetPath = `${SAS_URL}/${CONTAINER}/${userId}/${fileName}`;
  HEADER["x-ms-blob-content-type"] = CONST_HEADER(fileType);
  return await RNFetchBlob.fetch(
    "PUT",
    `${assetPath}?${SAS_TOKEN}`,
    HEADER,
    RNFetchBlob.wrap(localUri)
  )
    ?.uploadProgress(callBack)
    .then(() => {
      return assetPath;
    });
};

fileType = 'video' | image | pdf

let params: any = {
      fileType: 'image',
      localUri: image,
    };

generate Custom Id for Uniqueness or you can also use UUID

const customIdGenerator = (length: any) => {
  var result = "";
  var characters =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
  var charactersLength = characters.length;
  for (var i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength));
  }
  return result;
};

set Headers for different Files

const CONST_HEADER = (type: any) => {
  return type == 'image'
    ? `image/png`
    : type == 'video'
    ? 'video/mp4'
    : type == 'pdf' && 'application/pdf';
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM