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à rất 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.
  • Không bắt buộc, thông tin bổ sung về lỗi.

Mã lỗi chuẩn

Data Manager API sử dụng một nhóm mã lỗi chuẩn do gRPC và HTTP xác định. Các mã này cung cấp thông tin chung về loại lỗi. Trước tiên, bạn phải luôn kiểm tra mã này để hiểu rõ 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.

Mô hình nhanh chóng thất bại

Data Manager API sử dụng mô hình thất bại nhanh. Nếu một yêu cầu chứa lỗi cấu trúc hoặc nếu bất kỳ bản ghi nào không xác thực được cho một trường bắt buộc, thì toàn bộ yêu cầu sẽ không thành công và API sẽ không xử lý bất kỳ dữ liệu nào trong yêu cầu đó.

Mô hình thất bại nhanh khác với mô hình thất bại một phần trong một số API khác của Google, chẳng hạn như Google Ads API và Campaign Manager 360 API. Trong mô hình lỗi một phần, một yêu cầu sẽ thành công ngay cả khi một số bản ghi bị lỗi và phản hồi chứa thông tin chi tiết về lỗi cho các bản ghi không thành công.

Mặc dù lỗi một phần có thể thuận tiện, nhưng nó mang lại những rủi ro đáng kể vì mô hình lỗi một phần không chủ động cảnh báo cho bạn về các lỗi – bạn phải kiểm tra rõ ràng các lỗi trong từng phản hồi. Điều này có thể che giấu các vấn đề quan trọng vì một yêu cầu sẽ thành công ngay cả khi API từ chối nhiều hoặc thậm chí tất cả các bản ghi trong yêu cầu. Nếu một phần đáng kể của các bản ghi trong một yêu cầu có lỗi nhưng bạn không kiểm tra phản hồi, thì bạn có thể hoàn toàn không biết về các vấn đề trên diện rộng với dữ liệu của mình và chỉ phát hiện ra những vấn đề đó sau nhiều ngày hoặc nhiều tuần khi kết quả tích luỹ không phù hợp với kỳ vọng của bạn.

Mô hình thất bại nhanh giúp bạn tránh được những cạm bẫy này bằng cách cảnh báo ngay cho bạn về các vấn đề với dữ liệu hoặc quá trình tích hợp để bạn có thể thực hiện hành động thích hợp.

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 nội dung 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, Help và LocalizedMessage.

    • 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ợ.
    • Help và LocalizedMessage chứa các đường liên kết và thông tin khác để giúp bạn giải quyết lỗi.

    Ngoài ra, tải trọng BadRequest rất hữu ích cho các lỗi INVALID_ARGUMENT vì tải trọng này cung cấp thông tin về những trường gây ra lỗi.

Cảnh báo khi phân tích

Data Manager API chấp nhận nhiều yêu cầu nhập dữ liệu nhất có thể. Nếu bạn thêm dữ liệu không bắt buộc, thì lỗi xác thực cho những trường đó sẽ không khiến yêu cầu thất bại. Ví dụ: nếu một mặt hàng trong giỏ hàng bị thiếu mã sản phẩm của người bán, thì API sẽ xử lý phần còn lại của yêu cầu và trả về một cảnh báo.

Phản hồi thành công về việc truyền dữ liệu (mã trạng thái HTTP 200) bao gồm những cảnh báo này trong danh sách field_warnings. Mỗi mục là một đối tượng FieldWarning có các trường sau:

field

Vị trí của trường trong yêu cầu, theo cú pháp đường dẫn snake case.

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ụ: events.events[0].cart_data.items[0].merchant_product_id xác định một cảnh báo liên quan đến mặt hàng đầu tiên trong dữ liệu giỏ hàng của sự kiện đầu tiên trong yêu cầu.

description

Giải thích lý do giá trị được cung cấp gây ra cảnh báo.

reason

Giá trị enum WarningReason xác định loại cảnh báo.

Ví dụ về FieldWarning

Sau đây là một phản hồi mẫu cho yêu cầu tiếp nhận thành công có chứa một cảnh báo vì thiếu mã sản phẩm của người bán cho một trong các mặt hàng trong giỏ hàng.

{
  "requestId": "126365e1-16d0-4c81-9de9-f362711e250a",
  "fieldWarnings": [
    {
      "field": "events.events[0].cart_data.items[0].merchant_product_id",
      "description": "The merchant product ID is missing in the cart item.",
      "reason": "WARNING_REASON_CART_DATA_ITEM_MERCHANT_PRODUCT_ID_MISSING"
    }
  ]
}

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, theo cú pháp đường dẫn snake case.

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_id là account_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

Sau đâ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 thấy 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 có 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á hex 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"
          }
        ]
      }
    ]
  }
}

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 riêng biệ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 đám mây 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 có thể bật dịch vụ, trong 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.cloud.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.cloud.google.com/apis/api/datamanager.googleapis.com/overview?project=PROJECT_NUMBER"
        }
      },
      ...
    ]
  }
}

Help và LocalizedMessage

Kiểm tra tải trọng Help và LocalizedMessage để lấy đườ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à Help và LocalizedMessage cho lỗi PERMISSION_DENIED do sử dụng thông tin đăng nhập cho một dự án trên đám mây của Google Cloud mà Data Manager API không được bật. Tải trọng Help cho biết URL mà dịch vụ có thể được bật 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.cloud.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.cloud.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 API Console API activation",
            "url": "https://console.cloud.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 sử 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.ErrorInfo)
        {
            Google.Rpc.ErrorInfo errorInfo = (Google.Rpc.ErrorInfo)detail;
            // Log the errorInfo.Reason and errorInfo.Metadata...

            // Log the details in the 'Metadata' map...
            foreach (
                KeyValuePair<String, String> metadataEntry in errorInfo.Metadata
            )
            {
                // Log the metadataEntry.Key and metadataEntry.Value...
            }
        }
        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.ApiException apiException) {
  // Fallback exception handler for other types of ApiException.

  // Gets the standard ErrorInfo payload from the exception.
  ErrorInfo errorInfo = apiException.getErrorDetails().getErrorInfo();
  // Log the 'reason' and 'domain'...

  // Log the details in the 'metadata' map...
  for (Entry<String, String> metadataEntry : errorInfo.getMetadataMap().entrySet()) {
    // Log the metadataEntry key and value...
  }

  // Gets the standard RequestInfo payload from the exception.
  RequestInfo requestInfo = invalidArgumentException.getErrorDetails().getRequestInfo();
  if (requestInfo != null) {
    String requestId = requestInfo.getRequestId();
    // Log the requestId...
  }
  ...
}

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 các 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 này là do vấn đề với quá trình triển khai (máy khách) hay vấn đề với API (máy chủ).

  • 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 lỗi 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, UNKNOWN và ABORTED.
  • Sử dụng thuật toán thời gian đợi luỹ thừa để chờ trong khoảng thời gian tăng dầ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 ứng dụng đồng thời thử lạ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 cho việc gỡ lỗi và báo cáo vấn đề cho nhóm hỗ trợ Google nếu cần.

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

Dựa trên mã và thông báo trong các 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.