用于C++的 Azure SDK 中的错误处理

Azure SDK for C++ 中的错误处理主要通过C++异常来实现。 此方法符合标准C++做法,并允许跨 SDK 明确错误报告和处理。 当C++应用程序与 Azure 服务交互时,由于身份验证问题、服务不可用、请求无效或资源约束等各种原因,作可能会失败。 SDK 将这些错误捕获为异常,这些异常提供有关失败的详细信息。

异常层次结构

核心异常类型

用于C++的 Azure SDK 使用异常类的层次结构,最重要的是:

  1. std::runtime_error - 从中继承Azure特定异常的基本C++标准异常。

  2. Azure::Core::RequestFailedException - 派生自 std::runtime_error,这是所有 Azure 服务请求失败的基本异常。 在 azure/core/exception.hpp 中定义,当对 Azure 服务的请求失败时,将引发此异常。 它提供:

    • HTTP 状态代码
    • 来自服务的错误代码
    • 错误消息
    • 请求 ID 用于故障排除
    • 原始 HTTP 响应
  3. Azure::Core::OperationCancelledException - 派生自 std::runtime_error,当一个操作被取消时(通常是通过上下文对象),会引发此异常。

  4. Azure::Core::Http::TransportException - 派生自 Azure::Core::RequestFailedExceptionHTTP 传输层中出现错误(例如连接失败)时,将引发此异常。

  5. Azure::Core::Credentials::AuthenticationException - 从 std::exception 派生,当 Azure 服务身份验证失败时,将引发此异常。

特定于服务的异常类型

不同的 Azure 服务扩展了基本异常类型,以提供特定于服务的错误信息:

  1. Azure::Storage::StorageException - 扩展 RequestFailedException,添加其他与存储相关的信息。 此异常包括:

    • 与存储相关的错误代码
    • 响应正文中的其他信息
    • 有关存储操作失败的详细信息
  2. Azure::Messaging::EventHubs::EventHubsException - 特定于事件中心操作的异常。 其中包括:

    • 错误条件(来自高级消息队列协议(AMQP)的符号值)
    • 错误说明
    • 状态代码
    • 有关错误是否为暂时性的信息

异常中的错误信息

RequestFailedException 类包含有关服务故障的丰富信息:

class RequestFailedException : public std::runtime_error {
public:
    // The entire HTTP raw response
    std::unique_ptr<Azure::Core::Http::RawResponse> RawResponse;
    
    // The HTTP response code
    Azure::Core::Http::HttpStatusCode StatusCode;
    
    // The HTTP reason phrase from the response
    std::string ReasonPhrase;
    
    // The client request header (x-ms-client-request-id) from the HTTP response
    std::string ClientRequestId;
    
    // The request ID header (x-ms-request-id) from the HTTP response
    std::string RequestId;
    
    // The error code from service returned in the HTTP response
    std::string ErrorCode;
    
    // The error message from the service returned in the HTTP response
    std::string Message;
    
    /* ... constructors and other methods ... */
};

特定于服务的异常可以添加额外的字段。 例如, StorageException 添加 AdditionalInformation

struct StorageException final : public Azure::Core::RequestFailedException {
    // Some storage-specific information in response body
    std::map<std::string, std::string> AdditionalInformation;
    
    /* ... constructors and other methods ... */
};

异常处理模式和示例

使用错误代码

服务异常包含 ErrorCode 可用于做出有关如何处理故障的决定的值。 下面是存储服务的一个示例:

try {
    containerClient.Delete();
}
catch (Azure::Storage::StorageException& e) {
    if (e.ErrorCode == "ContainerNotFound") {
        // Ignore the error if the container does not exist
    }
    else {
        // Handle other errors here
    }
}

处理基本异常

在 Azure SDK 中处理异常的基本模式:

try {
    // Perform an Azure SDK operation
    result = client.SomeOperation();
}
catch (Azure::Core::RequestFailedException const& e) {
    std::cout << "Request Failed Exception happened:" << std::endl << e.what() << std::endl;
    if (e.RawResponse) {
        std::cout << "Error Code: " << e.ErrorCode << std::endl;
        std::cout << "Error Message: " << e.Message << std::endl;
    }
    // Handle or rethrow as appropriate
}
catch (std::exception const& e) {
    std::cout << "Other exception: " << e.what() << std::endl;
    // Handle general exceptions
}

处理暂时性错误

某些服务(如事件中心)提供有关错误是否是暂时性的,允许重试逻辑的信息:

try {
    // EventHubs operation
}
catch (Azure::Messaging::EventHubs::EventHubsException& e) {
    if (e.IsTransient) {
        // Retry the operation after a delay
    }
    else {
        // Handle permanent failure
    }
}

SDK 为暂时性故障实现内部重试策略,但你想要在应用程序代码中处理特定情况。

服务特定的错误处理

对于存储服务(如 Blob、文件、队列等),你可以基于错误代码和 HTTP 状态码来处理错误:

try {
    shareClient.Delete();
}
catch (Azure::Storage::StorageException& e) {
    if (e.ErrorCode == "ShareNotFound") {
        // Ignore the error if the file share does not exist
    }
    else if (e.StatusCode == Azure::Core::Http::HttpStatusCode::Conflict) {
        // Handle conflict error (e.g., resource in use)
        std::cout << "Conflict error: " << e.Message << std::endl;
        
        // Check additional information
        for (auto const& info : e.AdditionalInformation) {
            std::cout << info.first << ": " << info.second << std::endl;
        }
    }
    else {
        // Handle other errors based on status code or error code
        std::cout << "Error: " << e.Message << " (Code: " << e.ErrorCode << ")" << std::endl;
    }
}

对于 Key Vault 操作,您可能需要单独处理身份验证异常:

try {
    // Key Vault operation
}
catch (Azure::Core::Credentials::AuthenticationException const& e) {
    std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
    // Handle authentication failure (e.g., invalid credentials)
}
catch (Azure::Core::RequestFailedException const& e) {
    std::cout << "Key Vault Client Exception happened:" << std::endl << e.Message << std::endl;
    // Handle Key Vault specific errors
}

线程安全注意事项

用于C++的 Azure SDK 保证客户端实例方法是线程安全的,彼此独立。 这意味着可以在多个线程之间安全地使用客户端实例,而无需同步。

处理跨线程的异常时,请记住:

  1. 除非正确同步,否则不应在线程之间共享异常对象
  2. 其中包括 RequestFailedException 一个复制构造函数,用于创建深层副本,当需要在线程之间传递异常信息时,可以使用该构造函数