前一篇文章中說到可以使用 restful API 讓前端網頁程式直接對 Azure Blob Storage 進行檔案上傳,不過 Blob Storage 的 restful API 在 put method 時有限制檔案大小必須小於 256 MB,本篇將教學如果遇到檔案大小超過256 MB 的時候需要怎麼處理。
如果使用一般的 put method 上傳檔案超過 256 MB 會收到類似下面的 response
<?xml version="1.0" encoding="utf-8"?> <Error> <Code>RequestBodyTooLarge</Code> <Message>The request body is too large and exceeds the maximum permissible limit. RequestId:184d0d5a-d01a-011b-11e8-21131f000000 Time:2020-05-04T13:50:39.8719457Z</Message> <MaxLimit>268435456</MaxLimit> </Error>
為了解決這個問題,上傳大於 256 GB 的檔案,就要分多個步驟處理
-
需要將檔案切成多份 (每份小於 256 GB),並且將每份都使用 Put Block 的 API 分批上傳
-
透過 Put Block List 將所有已上傳的 block 組在一起
一、將檔案切成多份,並且將每份都使用 Put Block 的 API 分批上傳
Put Block 就是將原本含有 sas 的 URL 後面加上 comp (值為 block) 與 blockid 這兩個參數
其中 blockid 是自己定義的值,但是有以下兩個限制:
-
格式要符合 Base64,並且長度限制要小於等於64
-
每個 blockid 之間的長度要相同
舉例原本含有 sas 的 url 是:
https://myaccount.blob.core.windows.net/container1/5e4ba47b?sv=2017-11-09&sr=b&se=2020-02-18T09:46:51Z&sp=rcwd&sig=KhqKo%2FP%2FhLarhZ3RAHGL4fvKF5iu5rHjEC1OUc1MKqw%3D
那這假如要是傳的檔案被切成了兩份,分別建立了兩個隨機的 block id 為 MTAwMA== 與 MTAwMQ==
則兩個上傳的URL就會是
https://myaccount.blob.core.windows.net/container1/5e4ba47b?sv=2017-11-09&sr=b&se=2020-02-18T09:46:51Z&sp=rcwd&sig=KhqKo%2FP%2FhLarhZ3RAHGL4fvKF5iu5rHjEC1OUc1MKqw%3D&comp=block&blockid=MTAwMA== https://myaccount.blob.core.windows.net/container1/5e4ba47b?sv=2017-11-09&sr=b&se=2020-02-18T09:46:51Z&sp=rcwd&sig=KhqKo%2FP%2FhLarhZ3RAHGL4fvKF5iu5rHjEC1OUc1MKqw%3D&comp=block&blockid=MTAwMQ==
對這兩個 url 使用 put method 上傳檔案
二、透過 Put Block List 將所有已上傳的 block 組在一起
當每個 block 都上傳完畢後,再透過 Put Block List 的 API 將這些 block 組合在一起更新進去,Put Block List 的 url 是含有 sas 的 blob url 後面加上 comp (值為blocklist) 這個參數
以上面的 sas url 為例,那 url 便是:
https://myaccount.blob.core.windows.net/container1/5e4ba47b?sv=2017-11-09&sr=b&se=2020-02-18T09:46:51Z&sp=rcwd&sig=KhqKo%2FP%2FhLarhZ3RAHGL4fvKF5iu5rHjEC1OUc1MKqw%3D&comp=blocklist
而 Put Block List 內容則是要描述使用哪些 block 來進行組合 (格式為 xml),以剛剛兩個 block id 為例,那內容就會是:
<?xml version="1.0" encoding="utf-8"?> <BlockList> <Latest>MTAwMA==</Latest> <Latest>MTAwMQ==</Latest> </BlockList>
javascript 程式碼範例:
let blobUrl = getBlobUrl(); let file = document.querySelector('#upload-file').files[0]; let fileReader = new FileReader(); fileReader.onload = async function() { let blockStart = 0; let blockSize = 52428800; // 每份 block 大小 (50MB) let blockIds = []; // 要更新的 block id while (blockStart < fileReader.result.byteLength) { let blockId = btoa(1000 + blockStart / blockSize); await axios.put(blobUrl + "&comp=block&blockid=" + blockId, fileReader.result.slice(blockStart, blockStart + blockSize), { headers: { 'x-ms-blob-type': 'BlockBlob' } }); blockIds.push(blockId); blockStart += blockSize; } if (blockIds.length > 0) { let content = '<?xml version="1.0" encoding="utf-8"?><BlockList><Latest>'; content += blockIds.join('</Latest><Latest>'); content += '</Latest></BlockList>'; await axios.put(blobUrl + "&comp=blocklist", content); console.log('上傳完畢'); } } fileReader.readAsArrayBuffer(file);