我正在使用 azure-sdk-for-cpp,并且在使用 CommitBlockList 时收到 400 XML指定在语法上无效。有没有办法可以看出 XML 出了什么问题? 我尝试读取日志,没有请求正文,我不知道出了什么问题。
void TestClass::Flush()
{
UploadBlock();
for (auto& task : tasks) {
if (task.valid()) {
task.get();
}
}
tasks.clear();
std::copy(uncomitted_blocks_ids.begin(), uncomitted_blocks_ids.end(),
std::back_inserter(committed_blocks_ids));
blob_client.AsBlockBlobClient().CommitBlockList(committed_blocks_ids);
uncomitted_blocks_ids.clear();
}
void TestClass::Close()
{
Flush();
committed_blocks_ids.clear();
uncomitted_blocks_ids.clear();
}
void TestClass::UploadBlock()
{
auto it= m_tasks.begin();
try {
for(; it != m_tasks.end(); /*++it*/) {
if(it->wait_for(std::chrono::seconds(0)) == std::future_status::ready ||
m_tasks.size() >= m_network_connections_max){
it->get();
it= m_tasks.erase(it);
}
else {
++it;
}
}
}
catch(::Azure::Storage::StorageException&) {
tasks.erase(it);
throw;
}
auto block_id = GetBlockId(std::to_string(block_count++));
m_tasks.push_back(std::async(std::launch::async, [this, block_data= m_buffer, block_id]() {
auto block_content = ::Azure::Core::IO::MemoryBodyStream(block_data.data(), block_data.size());
uncomitted_blocks_ids.push_back(block_id);
blob_client.AsBlockBlobClient().StageBlock(block_id, block_content);
}));
}
使用400 使用 CommitBlockList 时指定的 XML 在语法上无效
400
时指定的
CommitBlockList
XML 在语法上无效错误通常表示为提交块生成的 XML 有效负载无效或格式错误。您可以参考这两个 Microsoft 文档
DOC-1 和 DOC-2,以在 Azure Blob 存储中上传正确的上传块 Blob。
这里我使用了示例代码,它将上传文件并更正块 ID。
代码:
#include <azure/storage/blobs.hpp>
#include <fstream>
#include <future>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <chrono>
#include <openssl/evp.h> // OpenSSL for Base64 encoding
using namespace Azure::Storage::Blobs;
const int BlockSize = 4 * 1024 * 1024; // 4 MB blocks
const int MaxConcurrency = 8;
class TestClass {
public:
TestClass(BlockBlobClient blobClient)
: blob_client(blobClient), block_count(0) {}
void UploadBlock();
void Flush();
void Close();
private:
std::string Base64Encode(const std::string& input);
std::string GetBlockId(const std::string& blockNumber);
BlockBlobClient blob_client;
std::vector<std::future<void>> m_tasks; // Store async tasks
std::vector<std::string> uncomitted_blocks_ids; // Store uncommitted block IDs
std::vector<std::string> committed_blocks_ids; // Store committed block IDs
std::vector<uint8_t> m_buffer; // Buffer to hold file data
int block_count;
size_t m_network_connections_max = MaxConcurrency; // Max parallel uploads
};
std::string TestClass::Base64Encode(const std::string& input) {
size_t encoded_size = 4 * ((input.size() + 2) / 3);
std::string encoded_string(encoded_size, '\0');
int len = EVP_EncodeBlock(reinterpret_cast<unsigned char*>(&encoded_string[0]),
reinterpret_cast<const unsigned char*>(input.c_str()),
input.size());
encoded_string.resize(len); // Adjust to the actual length
return encoded_string;
}
std::string TestClass::GetBlockId(const std::string& blockNumber) {
std::stringstream ss;
ss << std::setw(8) << std::setfill('0') << blockNumber;
return Base64Encode(ss.str()); // Return Base64-encoded block ID
}
void TestClass::UploadBlock() {
// Read file content into m_buffer
std::ifstream file("C:\\Users\\v-vsettu\\Downloads\\sample5.pdf", std::ios::binary | std::ios::ate);
if (!file) {
std::cerr << "Failed to open file." << std::endl;
throw std::runtime_error("Failed to open file.");
}
std::streamsize file_size = file.tellg();
file.seekg(0, std::ios::beg);
m_buffer.resize(file_size);
if (!file.read(reinterpret_cast<char*>(m_buffer.data()), file_size)) {
std::cerr << "Failed to read file." << std::endl;
throw std::runtime_error("Failed to read file.");
}
// Split the buffer into blocks and upload
int offset = 0;
while (offset < file_size) {
int current_block_size = std::min(BlockSize, static_cast<int>(file_size) - offset);
std::vector<uint8_t> block_data(m_buffer.begin() + offset, m_buffer.begin() + offset + current_block_size);
auto block_id = GetBlockId(std::to_string(block_count++));
uncomitted_blocks_ids.push_back(block_id);
m_tasks.push_back(std::async(std::launch::async, [this, block_data = block_data, block_id]() {
auto block_content = Azure::Core::IO::MemoryBodyStream(block_data.data(), block_data.size());
blob_client.StageBlock(block_id, block_content);
}));
offset += current_block_size;
}
}
void TestClass::Flush() {
// Wait for all tasks to complete
for (auto& task : m_tasks) {
if (task.valid()) {
task.get();
}
}
// Clear tasks after completion
m_tasks.clear();
// Commit the block list
blob_client.CommitBlockList(uncomitted_blocks_ids);
// Add uncommitted blocks to committed list
std::copy(uncomitted_blocks_ids.begin(), uncomitted_blocks_ids.end(),
std::back_inserter(committed_blocks_ids));
// Clear the uncommitted blocks list
uncomitted_blocks_ids.clear();
std::cout << "Upload completed successfully." << std::endl;
}
void TestClass::Close() {
Flush();
committed_blocks_ids.clear();
uncomitted_blocks_ids.clear();
}
int main() {
// Define your connection string, container/blob name, and file path.
std::string connection_string = "xxxxx";
std::string container_name = "data";
std::string blob_name = "test.pdf";
// Create a BlockBlobClient using the connection string.
BlobContainerClient container_client = BlobContainerClient::CreateFromConnectionString(connection_string, container_name);
BlockBlobClient block_blob_client = container_client.GetBlockBlobClient(blob_name);
// Create an instance of TestClass
TestClass test_class(block_blob_client);
// Perform the upload with parallelism.
test_class.UploadBlock();
test_class.Flush();
return 0;
}
输出:
Upload completed successfully.
传送门: