Tìm hiểu về lỗi API

Hướng dẫn này giải thích cách Data Manager API xử lý và truyền đạt lỗi. Việc hiểu rõ cấu trúc và ý nghĩa của các lỗi API là điều quan trọng để xây dựng các ứng dụng mạnh mẽ có thể xử lý các vấn đề một cách hiệu quả, từ đầu vào không hợp lệ cho đến tình trạng dịch vụ tạm thời không hoạt động.

Data Manager API tuân theo mô hình lỗi API chuẩn của Google, dựa trên mã trạng thái gRPC. Mỗi phản hồi API dẫn đến lỗi đều bao gồm một đối tượng Status có:

  • Mã lỗi bằng số.
  • Một thông báo lỗi.
  • Thông tin chi tiết bổ sung không bắt buộc về lỗi.

Mã lỗi chuẩn

Data Manager API sử dụng một bộ mã lỗi chuẩn do gRPC và HTTP xác định. Các mã này cho biết loại lỗi ở cấp độ cao. Bạn nên luôn kiểm tra mã này trước để hiểu bản chất cơ bản của vấn đề.

Để biết thêm thông tin chi tiết về các mã này, hãy xem Hướng dẫn thiết kế API – Mã lỗi.

Xử lý lỗi

Hãy làm theo các bước sau khi yêu cầu không thành công:

  1. Kiểm tra mã lỗi để tìm loại lỗi.

    • Nếu bạn sử dụng gRPC, mã lỗi sẽ nằm trong trường code của Status. Nếu bạn sử dụng một thư viện ứng dụng, thì thư viện đó có thể khai báo một loại ngoại lệ cụ thể tương ứng với mã lỗi. Ví dụ: thư viện ứng dụng cho Java sẽ gửi một com.google.api.gax.rpc.InvalidArgumentException nếu mã lỗi là INVALID_ARGUMENT.
    • Nếu bạn sử dụng REST, mã lỗi sẽ nằm trong phản hồi lỗi tại error.status và trạng thái HTTP tương ứng nằm tại error.code.
  2. Kiểm tra tải trọng chi tiết tiêu chuẩn để biết mã lỗi. Tải trọng chi tiết tiêu chuẩn là một nhóm thông báo về các lỗi từ API của Google. Chúng cung cấp cho bạn thông tin chi tiết về lỗi theo cách có cấu trúc và nhất quán. Mỗi lỗi từ Data Manager API có thể có nhiều thông báo tải trọng chi tiết tiêu chuẩn. Thư viện ứng dụng Data Manager API có các phương thức trợ giúp để lấy tải trọng chi tiết tiêu chuẩn từ một lỗi.

    Bất kể mã lỗi là gì, bạn nên kiểm tra và ghi nhật ký tải trọng ErrorInfo, RequestInfo, HelpLocalizedMessage.

    • ErrorInfo có thông tin có thể không có trong các tải trọng khác.
    • RequestInfo có mã yêu cầu. Mã này sẽ hữu ích nếu bạn cần liên hệ với nhóm hỗ trợ.
    • HelpLocalizedMessage chứa các đường liên kết và thông tin chi tiết khác để giúp bạn giải quyết lỗi.

    Ngoài ra, các tải trọng BadRequest, QuotaFailureRetryInfo rất hữu ích cho các mã lỗi cụ thể:

    • Nếu mã trạng thái là INVALID_ARGUMENT, hãy kiểm tra tải trọng BadRequest để biết thông tin về những trường gây ra lỗi.
    • Nếu mã trạng thái là RESOURCE_EXHAUSTED, hãy kiểm tra tải trọng QuotaFailureRetryInfo để biết thông tin về hạn mức và đề xuất về độ trễ khi thử lại.

Tải trọng chi tiết tiêu chuẩn

Các tải trọng chi tiết tiêu chuẩn phổ biến nhất cho Data Manager API là:

BadRequest

Kiểm tra tải trọng BadRequest khi một yêu cầu không thành công với INVALID_ARGUMENT (mã trạng thái HTTP 400).

Thông báo BadRequest cho biết yêu cầu có các trường có giá trị không hợp lệ hoặc thiếu giá trị cho một trường bắt buộc. Kiểm tra danh sách field_violations trong BadRequest để biết những trường nào có lỗi. Mỗi mục field_violations đều có thông tin giúp bạn khắc phục lỗi:

field

Vị trí của trường trong yêu cầu, sử dụng cú pháp đường dẫn theo quy tắc viết hoa chữ cái đầu của từ thứ hai.

Nếu một đường dẫn trỏ đến một mục trong danh sách (trường repeated), thì chỉ mục của mục đó sẽ xuất hiện trong dấu ngoặc vuông ([...]) sau tên của danh sách.

Ví dụ: destinations[0].operating_account.account_idaccount_id trong operating_account của mục đầu tiên trong danh sách destinations.

description

Giải thích lý do giá trị đó gây ra lỗi.

reason

Enum ErrorReason, chẳng hạn như INVALID_HEX_ENCODING hoặc INVALID_CURRENCY_CODE.

Ví dụ về BadRequest

Dưới đây là một phản hồi mẫu cho lỗi INVALID_ARGUMENT kèm theo thông báo BadRequest. field_violations cho biết lỗi là accountId không phải là một số. Giá trị field destinations[0].login_account.account_id cho biết accountId có lỗi vi phạm trường nằm trong login_account của mục đầu tiên trong danh sách destinations.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-a8896317-069f-4198-afed-182a3872a660"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "destinations[0].login_account.account_id",
            "description": "String is not a valid number.",
            "reason": "INVALID_NUMBER_FORMAT"
          }
        ]
      }
    ]
  }
}

Sau đây là một phản hồi mẫu khác từ lỗi INVALID_ARGUMENT kèm theo thông báo BadRequest. Trong trường hợp này, danh sách field_violations cho thấy 2 lỗi:

  1. event đầu tiên có một giá trị không được mã hoá hex trên giá trị nhận dạng người dùng thứ hai của sự kiện.

  2. event thứ hai có một giá trị không được mã hoá theo hệ thập lục trên giá trị nhận dạng người dùng thứ ba của sự kiện.

{
  "error": {
    "code": 400,
    "message": "There was a problem with the request.",
    "status": "INVALID_ARGUMENT",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "INVALID_ARGUMENT",
        "domain": "datamanager.googleapis.com",
        "metadata": {
          "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
        }
      },
      {
        "@type": "type.googleapis.com/google.rpc.RequestInfo",
        "requestId": "t-6bc8fb83-d648-4942-9c49-2604276638d8"
      },
      {
        "@type": "type.googleapis.com/google.rpc.BadRequest",
        "fieldViolations": [
          {
            "field": "events.events[0].user_data.user_identifiers[1]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          },
          {
            "field": "events.events[1].user_data.user_identifiers[2]",
            "description": "The HEX encoded value is malformed.",
            "reason": "INVALID_HEX_ENCODING"
          }
        ]
      }
    ]
  }
}

QuotaFailureRetryInfo

Kiểm tra tải trọng QuotaFailureRetryInfo khi một yêu cầu không thành công với RESOURCE_EXHAUSTED (mã trạng thái HTTP 429).

Thông báo QuotaFailure cho biết một tài nguyên đã hết (ví dụ: bạn đã vượt quá hạn mức) hoặc hệ thống đang quá tải. Kiểm tra danh sách violations để xác định những hạn mức đã vượt quá.

Lỗi cũng có thể chứa thông báo RetryInfo, cho biết retry_delay được đề xuất để thử lại yêu cầu.

RequestInfo

Kiểm tra tải trọng RequestInfo bất cứ khi nào yêu cầu không thành công. RequestInfo chứa request_id giúp xác định duy nhất yêu cầu API của bạn.

{
  "@type": "type.googleapis.com/google.rpc.RequestInfo",
  "requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}

Khi ghi nhật ký lỗi hoặc liên hệ với nhóm hỗ trợ, hãy nhớ cung cấp mã yêu cầu để giúp chẩn đoán vấn đề.

ErrorInfo

Kiểm tra thông báo ErrorInfo để truy xuất thông tin bổ sung có thể không được ghi lại trong các tải trọng chi tiết tiêu chuẩn khác. Tải trọng ErrorInfo chứa một bản đồ metadata có thông tin về lỗi.

Ví dụ: đây là ErrorInfo cho lỗi PERMISSION_DENIED do sử dụng thông tin đăng nhập cho một dự án trên Google Cloud mà Data Manager API không được bật. ErrorInfo cung cấp thêm thông tin về lỗi, chẳng hạn như:

  • Dự án liên kết với yêu cầu, trong metadata.consumer.
  • Tên của dịch vụ, trong metadata.serviceTitle.
  • URL nơi bạn có thể bật dịch vụ này, trong phần metadata.activationUrl.
{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.ErrorInfo",
        "reason": "SERVICE_DISABLED",
        "domain": "googleapis.com",
        "metadata": {
          "consumer": "projects/PROJECT_NUMBER",
          "service": "datamanager.googleapis.com",
          "containerInfo": "PROJECT_NUMBER",
          "serviceTitle": "Data Manager API",
          "activationUrl": "https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

HelpLocalizedMessage

Kiểm tra tải trọng HelpLocalizedMessage để lấy các đường liên kết đến tài liệu và thông báo lỗi bằng ngôn ngữ địa phương giúp bạn hiểu và khắc phục lỗi.

Ví dụ: sau đây là HelpLocalizedMessage cho lỗi PERMISSION_DENIED do sử dụng thông tin đăng nhập cho một dự án trên Google Cloud mà Data Manager API không được bật. Tải trọng Help cho biết URL mà bạn có thể bật dịch vụ và LocalizedMessage có nội dung mô tả về lỗi.

{
  "error": {
    "code": 403,
    "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.",
    "status": "PERMISSION_DENIED",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
        "locale": "en-US",
        "message": "Data Manager API has not been used in project PROJECT_NUMBER before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
      },
      {
        "@type": "type.googleapis.com/google.rpc.Help",
        "links": [
          {
            "description": "Google developers console API activation",
            "url": "https://console.developers.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
          }
        ]
      },
      ...
    ]
  }
}

Xem thông tin chi tiết về lỗi truy cập

Nếu bạn đang sử dụng một trong các thư viện ứng dụng, hãy dùng các phương thức trợ giúp để nhận tải trọng chi tiết tiêu chuẩn.

.NET

try {
    // Send API request
}
catch (Grpc.Core.RpcException rpcException)
{
    Console.WriteLine($"Exception encountered: {rpcException.Message}");
    var statusDetails =
        Google.Api.Gax.Grpc.RpcExceptionExtensions.GetAllStatusDetails(
            rpcException
        );
    foreach (var detail in statusDetails)
    {
        if (detail is Google.Rpc.BadRequest)
        {
            Google.Rpc.BadRequest badRequest = (Google.Rpc.BadRequest)detail;
            foreach (
                BadRequest.Types.FieldViolation? fieldViolation in badRequest.FieldViolations
            )
            {
                // Access attributes such as fieldViolation!.Reason and fieldViolation!.Field
            }
        }
        else if (detail is Google.Rpc.RequestInfo)
        {
            Google.Rpc.RequestInfo requestInfo = (Google.Rpc.RequestInfo)detail;
            string requestId = requestInfo.RequestId;
            // Log the requestId...
        }
        else if (detail is Google.Rpc.QuotaFailure)
        {
            Google.Rpc.QuotaFailure quotaFailure = (Google.Rpc.QuotaFailure)detail;
            foreach (
                Google.Rpc.QuotaFailure.Types.Violation violation in quotaFailure.Violations
            )
            {
                // Access attributes such as violation.Subject and violation.QuotaId
            }
        }
        else
        {
            // ...
        }
    }
}

Java

try {
  // Send API request
} catch (com.google.api.gax.rpc.InvalidArgumentException invalidArgumentException) {
  // Gets the standard BadRequest payload from the exception.
  BadRequest badRequest = invalidArgumentException.getErrorDetails().getBadRequest();
  for (int i = 0; i < badRequest.getFieldViolationsCount(); i++) {
    FieldViolation fieldViolation = badRequest.getFieldViolations(i);
    // Access attributes such as fieldViolation.getField() and fieldViolation.getReason()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.QuotaFailureException quotaFailureException) {
  // Gets the standard QuotaFailure payload from the exception.
  QuotaFailure quotaFailure = quotaFailureException.getErrorDetails().getQuotaFailure();
  for (int i = 0; i < quotaFailure.getViolationsCount(); i++) {
    QuotaFailure.Violation violation = quotaFailure.getViolations(i);
    // Access attributes such as violation.getSubject() and violation.getQuotaId()
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = quotaFailureException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
} catch (com.google.api.gax.rpc.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.
  ...
}

Các phương pháp hay nhất để xử lý lỗi

Để tạo các ứng dụng có khả năng phục hồi, hãy triển khai các phương pháp hay nhất sau đây.

Kiểm tra thông tin chi tiết về lỗi
Luôn tìm một trong những tải trọng chi tiết tiêu chuẩn, chẳng hạn như BadRequest. Mỗi tải trọng chi tiết tiêu chuẩn đều chứa thông tin giúp bạn hiểu rõ nguyên nhân gây ra lỗi.
Phân biệt lỗi máy khách với lỗi máy chủ

Xác định xem lỗi có phải do vấn đề với quá trình triển khai (máy khách) hay vấn đề với API (máy chủ) gây ra hay không.

  • Lỗi phía máy khách: Các mã như INVALID_ARGUMENT, NOT_FOUND, PERMISSION_DENIED, FAILED_PRECONDITION, UNAUTHENTICATED. Những lỗi này yêu cầu bạn thay đổi yêu cầu hoặc trạng thái/thông tin đăng nhập của ứng dụng. Đừng thử lại yêu cầu mà không giải quyết vấn đề.
  • Lỗi máy chủ: Các mã như UNAVAILABLE, INTERNAL, DEADLINE_EXCEEDED, UNKNOWN. Những mã này cho thấy dịch vụ API đang gặp vấn đề tạm thời.
Triển khai chiến lược thử lại

Xác định xem có thể thử lại lỗi hay không và sử dụng chiến lược thử lại.

  • Chỉ thử lại đối với các lỗi máy chủ tạm thời như UNAVAILABLE, DEADLINE_EXCEEDED, INTERNAL, UNKNOWNABORTED.
  • Sử dụng thuật toán đợi luỹ tuyến để chờ khoảng thời gian tăng lên giữa các lần thử lại. Điều này giúp tránh gây quá tải cho một dịch vụ vốn đã chịu nhiều áp lực. Ví dụ: đợi 1 giây, sau đó đợi 2 giây, rồi đợi 4 giây, tiếp tục cho đến khi đạt đến số lần thử lại tối đa hoặc tổng thời gian chờ.
  • Thêm một lượng nhỏ "độ trễ" ngẫu nhiên vào độ trễ rút lui để ngăn chặn vấn đề "đàn gia súc" khi nhiều máy khách thử lại đồng thời.
Ghi nhật ký đầy đủ

Ghi lại toàn bộ phản hồi lỗi, bao gồm tất cả tải trọng chi tiết tiêu chuẩn, đặc biệt là mã yêu cầu. Thông tin này rất cần thiết để gỡ lỗi và báo cáo vấn đề cho nhóm hỗ trợ của Google nếu cần.

Đưa ra ý kiến phản hồi của người dùng

Dựa trên các mã và thông báo trong tải trọng chi tiết tiêu chuẩn, hãy cung cấp thông tin phản hồi rõ ràng và hữu ích cho người dùng ứng dụng của bạn. Ví dụ: thay vì chỉ nói "Đã xảy ra lỗi", bạn có thể nói "Thiếu mã giao dịch" hoặc "Không tìm thấy mã tài khoản của đích đến".

Bằng cách làm theo các nguyên tắc này, bạn có thể chẩn đoán và xử lý hiệu quả các lỗi do Data Manager API trả về, nhờ đó tạo ra các ứng dụng ổn định và thân thiện với người dùng hơn.