يشرح هذا الدليل كيفية تعامل Data Manager API مع الأخطاء وكيفية الإبلاغ عنها. إنّ فهم بنية أخطاء واجهة برمجة التطبيقات ومعناها أمر بالغ الأهمية لإنشاء تطبيقات قوية يمكنها معالجة المشاكل بشكل سليم، بدءًا من الإدخال غير الصالح وصولاً إلى عدم توفّر الخدمة مؤقتًا.
تتّبع Data Manager API نموذج الخطأ العادي لواجهة Google API، الذي يستند
إلى رموز حالة gRPC. يتضمّن كل ردّ من واجهة برمجة التطبيقات يؤدي إلى حدوث خطأ كائن Status يتضمّن ما يلي:
- رمز خطأ رقمي
- رسالة خطأ
- تفاصيل إضافية اختيارية عن الخطأ
رموز الخطأ الأساسية
تستخدِم Data Manager API مجموعة من رموز الخطأ الأساسية التي تحدّدها gRPC وHTTP. تقدّم هذه الرموز إشارة عالية المستوى إلى نوع الخطأ. يجب دائمًا التحقّق من هذا الرمز أولاً لفهم الطبيعة الأساسية للمشكلة.
لمزيد من التفاصيل حول هذه الرموز، يُرجى الاطّلاع على دليل تصميم واجهة برمجة التطبيقات - رموز الخطأ.
نموذج "الفشل السريع"
تستخدِم Data Manager API نموذج "الفشل السريع". إذا تعذّر إجراء عملية التحقّق الأساسية من أي سجلّ في الطلب، سيتعذّر تنفيذ الطلب بالكامل، ولن تعالج واجهة برمجة التطبيقات أيًا من البيانات في هذا الطلب.
يختلف نموذج "الفشل السريع" عن نموذج "الفشل الجزئي" في بعض واجهات برمجة التطبيقات الأخرى من Google ، مثل Google Ads API و Campaign Manager 360 API. في نموذج "الفشل الجزئي"، ينجح الطلب حتى إذا كانت بعض السجلات تتضمّن أخطاء، ويحتوي الردّ على تفاصيل الخطأ للسجلات التي تعذّر تنفيذها.
على الرغم من أنّ نموذج "الفشل الجزئي" قد يكون مناسبًا، إلا أنّه ينطوي على مخاطر كبيرة لأنّه لا يُنبّهك بشكل استباقي إلى الأخطاء، بل يجب التحقّق من الأخطاء في كل ردّ بشكل صريح. يمكن أن يؤدي ذلك إلى إخفاء المشاكل المهمة لأنّ الطلب ينجح حتى إذا رفضت واجهة برمجة التطبيقات العديد من السجلات في الطلب أو حتى جميعها. إذا كان جزء كبير من السجلات في الطلب يتضمّن أخطاء ولكن لم يتم فحص الردّ، قد لا تكون على علم تمامًا بالمشاكل المنتشرة في بياناتك، ولن تكتشف هذه المشاكل إلا بعد أيام أو أسابيع عندما لا تتطابق النتائج التراكمية مع توقعاتك.
يتجنّب نموذج "الفشل السريع" هذه المشاكل من خلال تنبيهك إلى المشاكل في بياناتك أو عملية الربط على الفور حتى تتمكّن من اتّخاذ الإجراء المناسب.
معالجة الأخطاء
اتّبِع الخطوات التالية عندما يتعذّر تنفيذ طلب:
تحقَّق من رمز الخطأ للعثور على نوع الخطأ.
- إذا كنت تستخدِم gRPC، يكون رمز الخطأ في الحقل
codeمنStatus. إذا كنتَ تستخدِم مكتبة عميل، قد تطرح نوعًا معيّنًا من الاستثناءات يتطابق مع رمز الخطأ. على سبيل المثال، تعرض مكتبة العميل للغة Java استثناءً من النوعcom.google.api.gax.rpc.InvalidArgumentExceptionإذا كان رمز الخطأ هوINVALID_ARGUMENT. - إذا كنت تستخدِم REST، يكون رمز الخطأ في ردّ الخطأ على
error.status، ويكون رمز حالة HTTP المقابل علىerror.code.
- إذا كنت تستخدِم gRPC، يكون رمز الخطأ في الحقل
تحقَّق من بيانات التفاصيل العادية لرمز الخطأ. بيانات التفاصيل العادية هي مجموعة من الرسائل للأخطاء الواردة من Google APIs. تقدّم لك تفاصيل الخطأ بطريقة منظَّمة ومتّسقة. قد يتضمّن كل خطأ من Data Manager API رسائل متعدّدة لبيانات التفاصيل العادية. تحتوي مكتبات عميل Data Manager API على طرق مساعِدة للحصول على بيانات التفاصيل العادية من الخطأ.
بغض النظر عن رمز الخطأ، ننصحك بالتحقّق من بيانات
ErrorInfoوRequestInfoوHelpو وLocalizedMessageوتسجيلها.- تحتوي
ErrorInfoعلى معلومات قد لا تكون متوفّرة في بيانات أخرى. RequestInfoيحتوي على رقم تعريف الطلب، وهو مفيد إذا كنت بحاجة إلى التواصل مع فريق الدعم.- تحتوي
HelpوLocalizedMessageعلى روابط وتفاصيل أخرى لمساعدتك في معالجة الخطأ.
بالإضافة إلى ذلك، تكون بيانات
BadRequestمفيدة للأخطاء من النوعINVALID_ARGUMENTلأنّها تقدّم معلومات عن الحقول التي تسبّبت في حدوث الخطأ.- تحتوي
بيانات التفاصيل العادية
في ما يلي بيانات التفاصيل العادية الأكثر شيوعًا في Data Manager API:
BadRequest
تحقَّق من بيانات BadRequest عندما يتعذّر تنفيذ طلب بسبب
INVALID_ARGUMENT (رمز حالة HTTP 400).
توضّح رسالة BadRequest أنّ الطلب كان يحتوي على حقول تتضمّن قيمًا غير صالحة، أو كان يفتقد قيمة لحقل مطلوب. تحقَّق من قائمة field_violations في BadRequest للعثور على الحقول التي تتضمّن أخطاء. يحتوي كل إدخال من field_violations على معلومات لمساعدتك في إصلاح الخطأ:
fieldموقع الحقل في الطلب، باستخدام بنية مسار camel case.
إذا كان المسار يشير إلى عنصر في قائمة (حقل
repeated)، يظهر فهرسه بين قوسَين مربّعَين ([...]) بعد اسم القائمة.على سبيل المثال،
destinations[0].operating_account.account_idهو الـaccount_idفي الـoperating_accountللعنصر الأول في قائمة الـdestinations.descriptionتفسير لسبب تسبُّب القيمة في حدوث خطأ
reasonتعداد
ErrorReason، مثلINVALID_HEX_ENCODINGأوINVALID_CURRENCY_CODE.
أمثلة على BadRequest
في ما يلي نموذج ردّ على خطأ من النوع INVALID_ARGUMENT مع رسالة BadRequest. توضّح field_violations أنّ الخطأ هو accountId ليس رقمًا. توضّح القيمة destinations[0].login_account.account_id للحقل field أنّ
accountId الذي يتضمّن انتهاكًا للحقل موجود في login_account للعنصر الأول
في قائمة 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"
}
]
}
]
}
}
في ما يلي نموذج ردّ آخر من خطأ من النوع INVALID_ARGUMENT مع رسالة BadRequest. في هذه الحالة، تعرض قائمة field_violations خطأَين:
يحتوي
eventالأول على قيمة غير مشفّرة بتنسيق سداسي عشري في معرّف المستخدِم الثاني للحدث .يحتوي
eventالثاني على قيمة غير مشفّرة بتنسيق سداسي عشري في معرّف المستخدِم الثالث للحدث .
{
"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
تحقَّق من بيانات RequestInfo في كل مرة يتعذّر فيها تنفيذ طلب. تحتوي RequestInfo على request_id الذي يحدّد طلب بيانات من واجهة برمجة التطبيقات بشكل فريد.
{
"@type": "type.googleapis.com/google.rpc.RequestInfo",
"requestId": "t-4490c640-dc5d-4c28-91c1-04a1cae0f49f"
}
عند تسجيل الأخطاء أو التواصل مع فريق الدعم، احرص على تضمين رقم تعريف الطلب للمساعدة في تشخيص المشاكل.
ErrorInfo
تحقَّق من رسالة ErrorInfo لاسترداد معلومات إضافية قد لا يتم تسجيلها في بيانات التفاصيل العادية الأخرى. تحتوي بيانات ErrorInfo على خريطة metadata تتضمّن معلومات عن الخطأ.
على سبيل المثال، في ما يلي ErrorInfo لفشل من النوع PERMISSION_DENIED ناتج عن استخدام بيانات اعتماد لمشروع على Google Cloud لم يتم تفعيل Data Manager API فيه. تقدّم ErrorInfo معلومات إضافية عن الخطأ، مثل:
- المشروع المرتبط بالطلب، ضِمن
metadata.consumer - اسم الخدمة، ضِمن
metadata.serviceTitle - عنوان URL الذي يمكن تفعيل الخدمة فيه، ضِمن
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 وLocalizedMessage
تحقَّق من بيانات Help وLocalizedMessage للحصول على روابط تؤدي إلى
المستندات ورسائل الخطأ المترجَمة التي تساعدك في فهم الخطأ وإصلاحه.
على سبيل المثال، في ما يلي Help وLocalizedMessage لفشل من النوع PERMISSION_DENIED ناتج عن استخدام بيانات اعتماد لمشروع على Google Cloud لم يتم تفعيل Data Manager API فيه. تعرض بيانات Help عنوان URL الذي يمكن تفعيل الخدمة فيه، وتحتوي LocalizedMessage على وصف للخطأ.
{
"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"
}
]
},
...
]
}
}
الوصول إلى تفاصيل الخطأ
إذا كنت تستخدِم إحدى مكتبات العميل، استخدِم الطرق المساعِدة للحصول على بيانات التفاصيل العادية.
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
{
// ...
}
}
}
جافا
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...
}
...
}
أفضل الممارسات لمعالجة الأخطاء
لإنشاء تطبيقات مرنة، اتّبِع أفضل الممارسات التالية.
- فحص تفاصيل الخطأ
- ابحث دائمًا عن إحدى بيانات التفاصيل العادية
، مثل
BadRequest. تحتوي كل بيانات تفاصيل عادية على معلومات لمساعدتك في فهم سبب الخطأ. - التمييز بين أخطاء العميل وأخطاء الخادم
حدِّد ما إذا كان الخطأ ناتجًا عن مشكلة في عملية التنفيذ (العميل) أو مشكلة في واجهة برمجة التطبيقات (الخادم).
- أخطاء العميل: رموز مثل
INVALID_ARGUMENTوNOT_FOUNDوPERMISSION_DENIEDوFAILED_PRECONDITIONوUNAUTHENTICATEDتتطلّب هذه الرموز إجراء تغييرات على الطلب أو حالة تطبيقك أو بيانات اعتماده. لا تعِد محاولة إرسال الطلب بدون معالجة المشكلة. - أخطاء الخادم: رموز مثل
UNAVAILABLEوINTERNALوDEADLINE_EXCEEDEDوUNKNOWNتشير هذه الرموز إلى مشكلة مؤقتة في خدمة واجهة برمجة التطبيقات.
- أخطاء العميل: رموز مثل
- تنفيذ استراتيجية إعادة المحاولة
حدِّد ما إذا كان يمكن إعادة محاولة تنفيذ الطلب، واستخدِم استراتيجية إعادة المحاولة.
- أعِد المحاولة فقط لأخطاء الخادم المؤقتة، مثل
UNAVAILABLEوDEADLINE_EXCEEDEDوINTERNALوUNKNOWNوABORTED. - استخدِم خوارزمية الرقود الأسي لانتظار فترات متزايدة بين عمليات إعادة المحاولة. يساعد ذلك في تجنُّب إرهاق خدمة متأثرة أصلاً. على سبيل المثال، انتظِر ثانية واحدة، ثم ثانيتَين، ثم 4 ثوانٍ، واستمر في ذلك حتى الوصول إلى الحد الأقصى لعدد عمليات إعادة المحاولة أو إجمالي وقت الانتظار.
- أضِف مقدارًا صغيرًا عشوائيًا من "التذبذب" إلى فترات الرقود لتجنُّب مشكلة "القطيع الصاخب" حيث يعيد العديد من العملاء المحاولة في الوقت نفسه.
- أعِد المحاولة فقط لأخطاء الخادم المؤقتة، مثل
- التسجيل بدقة
سجِّل ردّ الخطأ الكامل، بما في ذلك جميع بيانات التفاصيل العادية، وخاصةً رقم تعريف الطلب. هذه المعلومات ضرورية لتحديد المشاكل وحلّها والإبلاغ عنها إلى فريق دعم Google إذا لزم الأمر.
- تقديم ملاحظات للمستخدمين
استنادًا إلى الرموز والرسائل في بيانات التفاصيل العادية، قدِّم ملاحظات واضحة و مفيدة لمستخدمي تطبيقك. على سبيل المثال، بدلاً من "حدث خطأ"، يمكنك كتابة "لم يتم العثور على رقم تعريف المعاملة" أو "لم يتم العثور على رقم تعريف حساب الوجهة".
باتّباع هذه الإرشادات، يمكنك تشخيص الأخطاء التي تعرضها Data Manager API ومعالجتها بفعالية، ما يؤدي إلى إنشاء تطبيقات أكثر استقرارًا وسهولة في الاستخدام.