Los errores del SDK de Admin se dividen en dos categorías:
- Errores de programación: Son errores de programación y configuración en
la aplicación del usuario. La mayoría de las veces ocurren debido a un uso incorrecto del SDK.
(como pasar
null
a un método que no acepta valoresnull
) otros errores de configuración a nivel del proyecto o del SDK de Firebase (faltan credenciales, una cadena de ID de proyecto incorrecta, etcétera). - Errores de API: Estos incluir varios errores recuperables que ocurren en la implementación del SDK, los errores que se originan en los servicios de backend de Firebase y otros errores errores (como tiempos de espera) que pueden ocurrir al realizar llamadas RPC.
El SDK de Admin indica los errores de programación arrojando un error nativo del la plataforma en cuestión.
- Java: Muestra instancias de
IllegalArgumentException
yNullPointerException
. o un tipo de error de entorno de ejecución integrado similar. - Python: Genera instancias de
ValueError
,TypeError
o algún otro tipo de error integrado. - Go: Muestra un error genérico.
- .NET: Muestra instancias de
ArgumentException
,ArgumentNullException
o tipo de error integrado similar.
En la mayoría de las situaciones, no debes manejar explícitamente los errores de programación. En cambio, debes corregir tu código y configuración para evitar errores de programación por completo. Considera el siguiente fragmento de Java:
String uid = getUserInput();
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
Si el método getUserInput()
muestra null
o cadenas vacías, el
La API de FirebaseAuth.getUser()
arroja un IllegalArgumentException
. En lugar de
cuando lo manejas explícitamente, puedes mitigar el problema si te aseguras de que
El método getUserInput()
nunca muestra una cadena de UID no válida. Si no es así
posible, implementa la comprobación de argumentos necesaria en tu propio código de la siguiente manera:
String uid = getUserInput();
if (Strings.isNullOrEmpty(uid)) {
log.warn("UID must not be null or empty");
return;
}
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
Como principio, nunca vuelvas a intentarlo sobre los errores de programación. Cómo permitir la falla rápida la semántica sobre errores de programación suele ser la mejor forma de proceder porque expone errores de programación y configuración durante el desarrollo, donde se puedan corregir rápidamente. La falla rápida en este contexto puede significar dejar que los errores propagarse a un controlador de errores global en tu aplicación, o solo registrarlos con fines de auditoría seguidas de la finalización del flujo de ejecución actual (la aplicación no debería fallar). En general, sigue las instrucciones para manejar las prácticas recomendadas del lenguaje de programación y la aplicación en un framework de aplicaciones. Esto solo suele ser suficiente para abordar correctamente esta clase de errores.
Normalmente, la mayor parte de tus esfuerzos por solucionar los errores se centrarán en manejar las APIs de API errores. Algunos de estos errores se pueden recuperar, como los errores causados por un servicio no disponible temporalmente, y algunos incluso se anticipan durante el flujo normal de ejecución del programa, como la detección de tokens de ID no válidos o vencidos. En el resto de esta guía, se describe cómo el SDK de Admin representa esos errores de API. y las diversas opciones disponibles para manejarlos.
Estructura de un error de API
Un error de API consta de los siguientes componentes:
- Código de error
- Mensaje de error
- Código de error del servicio (opcional)
- Respuesta HTTP (opcional)
Se garantiza que cada error de API contenga un código y un mensaje de error. Ciertos errores de API también contienen un código de error de servicio que es específico de la API que generó el error. Por ejemplo, algunos errores generados por Firebase Auth La API contiene un código de error de servicio específico de Firebase Auth. Si el error fue el resultado de una respuesta de error HTTP de un servicio de backend, el error de API también contiene la respuesta HTTP correspondiente. Esto se puede usar para inspeccionar los encabezados y el contenido exactos de la respuesta original, lo cual es útil para la depuración, el registro o la implementación de lógica de manejo de errores más sofisticada.
Todas las implementaciones del SDK de Admin, excepto Node.js, proporcionan APIs que permiten el acceso los componentes anteriores de los errores de API.
Tipos de errores y APIs por lenguaje
Java
En Java, todos los errores de la API extienden la clase FirebaseException
. Puedes acceder a la
código de error, mensaje de error y la respuesta HTTP opcional de esta clase base.
public class FirebaseException extends Exception {
@NonNull
public ErrorCode getErrorCode() {
// ...
}
@NonNull
public String getMessage() {
// ...
}
@Nullable
public IncomingHttpResponse getHttpResponse() {
// ...
}
}
Las APIs que exponen los códigos de error del servicio proporcionan subclases específicas de la API de
FirebaseException
Por ejemplo, todos los métodos públicos en la API de FirebaseAuth
se declaran para arrojar instancias de FirebaseAuthException
. Puedes acceder a la
código de error del servicio de esta clase derivada.
public class FirebaseAuthException extends FirebaseException {
@Nullable
public AuthErrorCode getAuthErrorCode() {
// ...
}
}
Python
En Python, todos los errores de la API extienden el exceptions.FirebaseError
. Puedes acceder al código de error, al mensaje de error y al HTTP
respuesta de esta clase base.
class FirebaseError(Exception):
@property
def code(self):
# ...
@property
def message(self):
# ...
@property
def http_response(self):
# ...
Además, el SDK de Admin de Python ofrece clases derivadas separadas para cada código de error. Nos referimos a ellas como clases de error de la plataforma.
class InvalidArgumentError(FirebaseError):
# ...
class NotFoundError(FirebaseError):
# ...
Puedes capturar FirebaseError
en tu código y verificar su code
, o
Realiza una verificación de isinstance()
en una clase de error de la plataforma. También puedes escribir
código para detectar directamente tipos
de errores específicos de la plataforma. El último enfoque
lo que generará un código de manejo de errores más legible.
Las APIs que exponen los códigos de error del servicio proporcionan subclases de plataforma específicas de la API.
las clases de errores. Por ejemplo, todos los métodos públicos en el módulo auth
pueden generar
Los tipos de error específicos de la API, como auth.UserNotFoundError
y
auth.ExpiredIdTokenError
class UserNotFoundError(exceptions.NotFoundError):
# …
class ExpiredIdTokenError(exceptions.InvalidArgumentError):
# ...
Go
El SDK de Admin de Go proporciona un paquete errorutils
que contiene una serie de
que permiten probar códigos de error.
package errorutils
func IsInvalidArgument(err error) bool {
// ...
}
func IsNotFound(err error) bool {
// ...
}
El mensaje de error es simplemente la cadena que muestra la función Error()
de un
. Se puede acceder a la respuesta HTTP opcional llamando al
Función errorutils.HTTPResponse()
, que muestra un *http.Response
.
Es seguro pasar nil
o cualquier otro valor de error a la comprobación de errores
en el paquete errorutils
. Muestran true
si el argumento de entrada
contiene el código de error en cuestión y muestra false
para todo.
más. La función HTTPResponse()
tiene un comportamiento similar, pero muestra
nil
en lugar de false
.
Las APIs que exponen códigos de error del servicio proporcionan verificación de errores específicos de la API.
en los paquetes correspondientes. Por ejemplo, el paquete auth
proporciona las funciones IsUserNotFound()
y IsExpiredIDTokenError()
.
.NET
En .NET, todos los errores de la API extienden el FirebaseException
. Puedes acceder a la
código de error de la plataforma, el mensaje de error y la respuesta HTTP opcional de esta base
.
public class FirebaseException : Exception {
public ErrorCode ErrorCode { get; }
public String Message { get; }
public HttpResponseMessage HttpResponse { get; }
}
Las APIs que exponen los códigos de error del servicio proporcionan subclases específicas de la API de
FirebaseException
Por ejemplo, todos los métodos públicos en la API de FirebaseAuth
se declaran para arrojar instancias de FirebaseAuthException
.
Puedes acceder a la
código de error del servicio de esta clase derivada.
public class FirebaseAuthException : FirebaseException {
public AuthErrorCode AuthErrorCode { get; }
}
Códigos de error de la plataforma
Los códigos de error son comunes en todos los servicios de Firebase y Google Cloud Platform. En la siguiente tabla, se describen todos los posibles códigos de error de la plataforma. Este es un estable y se espera que permanezca sin cambios durante un largo período.
INVALID_ARGUMENT | El cliente especificó un argumento no válido. |
FAILED_PRECONDITION | La solicitud no se puede ejecutar en el estado actual del sistema, como borrar un directorio que no esté vacío. |
OUT_OF_RANGE | El cliente especificó un rango no válido. |
UNAUTHENTICATED | La solicitud no se autenticó debido a que falta un token de OAuth, no es válido o venció. |
PERMISSION_DENIED | El cliente no cuenta con los permisos necesarios. Esto puede suceder porque el token de OAuth no tiene los permisos correctos, el cliente no tiene permiso o la API no se habilitó para el proyecto del cliente. |
NOT_FOUND | No se encontró el recurso especificado o se rechazó la solicitud por motivos no divulgados, como la lista blanca. |
CONFLICTO | Conflicto de concurrencia, como conflicto de lectura-modificación-escritura. Solo se usa en algunos servicios heredados. La mayoría de los servicios usan ABORTED o ALREADY_EXISTS en lugar de esto. Consulta la documentación específica del servicio para saber cuál debes administrar en tu código. |
ABORTED | Conflicto de concurrencia, como conflicto de lectura-modificación-escritura. |
ALREADY_EXISTS | El recurso que el cliente intentó crear ya existe. |
RESOURCE_EXHAUSTED | Sin cuota de recursos o a punto de alcanzar el límite de frecuencia. |
CANCELADO | El cliente canceló la solicitud. |
DATA_LOSS | Daño o pérdida de datos no recuperable. El cliente debe informar el error al usuario. |
DESCONOCIDO | Error desconocido del servidor. Por lo general, un error de servidor.
Este código de error también se asigna a errores de análisis de respuestas locales (deserializar) y a una amplia gama de otros errores de E/S de bajo nivel que no son fáciles de diagnosticar. |
INTERNAL | Error interno del servidor. Por lo general, un error de servidor. |
UNAVAILABLE | Servicio no disponible. Por lo general, el servidor está temporalmente fuera de servicio.
Este código de error también se asigna a los errores de la red local (conexión rechazada, sin ruta al host). |
DEADLINE_EXCEEDED | Se excedió el plazo de la solicitud. Esto sucederá solo si el llamador establece una fecha límite que es más corta que la fecha límite predeterminada de la API de destino (es decir, la fecha límite solicitada no es suficiente para que el servidor procese la solicitud) y la solicitud no finalizó dentro del plazo establecido.
Este código de error también se asigna a la conexión local y a los tiempos de espera de lectura. |
La mayoría de las APIs solo pueden generar un subconjunto de los códigos de error anteriores. En cualquier caso, no se espera que manejen explícitamente todos estos códigos de error cuando implementar los controladores de errores. A la mayoría de las aplicaciones solo les interesaría de 1 a 2 códigos de error específicos y tratar todo lo demás como genérico e irrecuperable. falla.
Códigos de error específicos del servicio
Firebase Auth
CERTIFICATE_FETCH_FAILED | No se pudieron recuperar los certificados de clave pública necesarios para verificar un JWT (token de ID o cookie de sesión). |
EMAIL_ALREADY_EXISTS | Ya existe un usuario con el correo electrónico proporcionado. |
EXPIRED_ID_TOKEN | Venció el token de ID especificado para verifyIdToken() .
|
COOKIE_DE_SESSION_VENCIDA | Venció la cookie de sesión especificada para verifySessionCookie() .
|
INVALID_DYNAMIC_LINK_DOMAIN | El dominio del vínculo dinámico proporcionado no se configuró o no se autorizó para el proyecto actual. Se relaciona con las APIs de vínculos de acción de correo electrónico. |
INVALID_ID_TOKEN | El token de ID especificado en verifyIdToken() no es válido.
|
COOKIE_DE_SESSION_NO VÁLIDA | La cookie de sesión especificada para verifySessionCookie() no es válida.
|
PHONE_NUMBER_ALREADY_EXISTS | Ya existe un usuario con el número de teléfono proporcionado. |
REVOKED_ID_TOKEN | Se revoca el token de ID especificado en verifyIdToken() .
|
COCINA_DE_SESSION_REVOKED | Venció la cookie de sesión especificada para verifySessionCookie() .
|
URL CONTINUAR NO AUTORIZADA | El dominio de la URL de continuación no está en la lista blanca. Se relaciona con las APIs de vínculos de acción de correo electrónico. |
NO_ENCONTRADO_USUARIO | No se encontró ningún registro de usuario para el identificador en cuestión. |
Firebase Cloud Messaging
TERCER_PARTY_AUTH_ERROR | El certificado APNS o la clave de API de autenticación push web no eran válidos o no se encontraron. |
INVALID_ARGUMENT | Uno o más argumentos especificados en la solicitud no eran válidos. |
INTERNAL | Error interno del servidor. |
CUOTA_EXCEDAD | Se superó el límite de envío para el destino del mensaje. |
ID DE REMITENTE_MISMATCH | El ID de remitente autenticado es diferente del ID de remitente del token de registro. Por lo general, esto significa que el token de registro del remitente y el de destino no están en el mismo proyecto de Firebase. |
UNAVAILABLE | El servicio de Cloud Messaging no está disponible en este momento. |
NO REGISTRADO | Se canceló el registro de la instancia de app en FCM. Por lo general, esto significa que el token de registro de dispositivo ya no es válido y que se debe usar uno nuevo. |
Reintentos automáticos
El SDK de Admin reintenta automáticamente ciertos errores antes de exponerlos a los usuarios. En general, los siguientes tipos de errores se reintentan con transparencia:
- Todos los errores de API que se generan a partir de respuestas HTTP 503 (servicio no disponible).
- Algunos errores de API son el resultado de respuestas HTTP 500 (error interno del servidor).
- La mayoría de los errores de E/S de nivel bajo (conexión rechazada, restablecimiento de la conexión, etc.).
El SDK volverá a intentar cada uno de los errores anteriores hasta 5 veces (el intento original + 4 reintentos) con retirada exponencial. Puedes implementar tu propio reintento a nivel de la aplicación si lo deseas, pero no suele ser como en los productos necesarios.
Reintentar después de recibir asistencia
Las implementaciones de Go y .NET del SDK de Admin incluyen compatibilidad con
que controla el encabezado HTTP Retry-After
. Es decir, si la respuesta de error enviada por
los servidores de backend contienen el encabezado Retry-After
estándar, el SDK
respecto de que, al volver a intentarlo, siempre y cuando la duración de espera especificada no sea muy
por mucho tiempo. Si el encabezado Retry-After
indica un tiempo de espera muy largo, el SDK
omitirá los reintentos y arrojará el error de API correspondiente.
Actualmente, el SDK de Admin de Python no es compatible con el encabezado Retry-After
.
solo admite una retirada exponencial simple
Ejemplos de manejo de errores de la API
Implementa un controlador de errores genérico
En la mayoría de los casos, lo que deseas es un controlador de errores genérico que detecte una amplia varios errores para evitar la finalización inesperada del flujo del programa debido a una Error de API. Estos controladores, por lo general, registran los errores con fines de auditoría o invocar alguna otra rutina predeterminada de manejo de errores para todas las APIs encontradas errores. No están necesariamente interesados en los diferentes códigos de error ni en el las razones que pueden haber causado el error.
Java
try {
FirebaseToken token = FirebaseAuth.getInstance().verifyIdToken(idToken);
performPrivilegedOperation(token.getUid());
} catch (FirebaseAuthException ex) {
System.err.println("Failed to verify ID token: " + ex.getMessage());
}
Python
try:
token = auth.verify_id_token(idToken)
perform_privileged_pperation(token.uid)
except exceptions.FirebaseError as ex:
print(f'Failed to verify ID token: {ex}')
Go
token, err := client.VerifyIDToken(ctx, idToken)
if err != nil {
log.Printf("Failed to verify ID token: %v", err)
return
}
performPrivilegedOperation(token)
.Net
try
{
var token = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
PerformPrivilegedOperation(token.getUid());
}
catch (FirebaseAuthException ex)
{
Conole.WriteLine($"Failed to verify ID token: {ex.Message}");
}
Verificar códigos de error
En algunos casos, querrás inspeccionar los códigos de error exactos y, luego, invocar diferentes rutinas de manejo de errores adaptados al contexto. En el siguiente ejemplo, tener un controlador de errores que registre mensajes de error más específicos según el código de error del servicio.
Java
try {
FirebaseToken token = FirebaseAuth.getInstance().verifyIdToken(idToken);
performPrivilegedOperation(token.getUid());
} catch (FirebaseAuthException ex) {
if (ex.getAuthErrorCode() == AuthErrorCode.ID_TOKEN_EXPIRED) {
System.err.println("ID token has expired");
} else if (ex.getAuthErrorCode() == AuthErrorCode.ID_TOKEN_INVALID) {
System.err.println("ID token is malformed or invalid");
} else {
System.err.println("Failed to verify ID token: " + ex.getMessage());
}
}
Python
try:
token = auth.verify_id_token(idToken)
perform_privileged_operation(token.uid)
except auth.ExpiredIdTokenError:
print('ID token has expired')
except auth.InvalidIdTokenError:
print('ID token is malformed or invalid')
except exceptions.FirebaseError as ex:
print(f'Failed to verify ID token: {ex}')
Go
token, err := client.VerifyIDToken(ctx, idToken)
if auth.IsIDTokenExpired(err) {
log.Print("ID token has expired")
return
}
if auth.IsIDTokenInvalid(err) {
log.Print("ID token is malformed or invalid")
return
}
if err != nil {
log.Printf("Failed to verify ID token: %v", err)
return
}
performPrivilegedOperation(token)
.Net
try
{
var token = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
PerformPrivilegedOperation(token.getUid());
}
catch (FirebaseAuthException ex)
{
if (ex.AuthErrorCode == AuthErrorCode.ExpiredIdToken)
{
Console.WriteLine("ID token has expired");
}
else if (ex.AuthErrorCode == AuthErrorCode.InvalidIdToken)
{
Console.WriteLine("ID token is malformed or invalid");
}
else
{
Conole.WriteLine($"Failed to verify ID token: {ex.Message}");
}
}
Este es otro ejemplo en el que verificamos los códigos de error de nivel superior y del servicio:
Java
try {
FirebaseMessaging.getInstance().send(createMyMessage());
} catch (FirebaseMessagingException ex){
if (ex.getMessagingErrorCode() == MessagingErrorCode.UNREGISTERED) {
System.err.println("App instance has been unregistered");
removeTokenFromDatabase();
} else if (ex.getErrorCode() == ErrorCode.Unavailable) {
System.err.println("FCM service is temporarily unavailable");
scheduleForRetryInAnHour();
} else {
System.err.println("Failed to send notification: " + ex.getMessage());
}
}
Python
try:
messaging.send(create_my_message())
except messaging.UnregisteredError:
print('App instance has been unregistered')
remove_token_from_database()
except exceptions.UnavailableError:
print('FCM service is temporarily unavailable')
schedule_for_retry_in_an_hour()
except exceptions.FirebaseError as ex:
print(f'Failed to send notification: {ex}')
Go
_, err := client.Send(ctx, createMyMessage())
if messaging.IsUnregistered(err) {
log.Print("App instance has been unregistered")
removeTokenFromDatabase()
return
}
if errorutils.IsUnavailable(err) {
log.Print("FCM service is temporarily unavailable")
scheduleForRetryInAnHour()
return
}
if err != nil {
log.Printf("Failed to send notification: %v", err)
return
}
.Net
try
{
await FirebaseMessaging.DefaultInstance.SendAsync(createMyMessage());
}
catch (FirebaseMessagingException ex)
{
if (ex.MessagingErrorCode == MessagingErrorCode.UNREGISTERED)
{
Console.WriteLine("App instance has been unregistered");
removeTokenFromDatabase();
}
else if (ex.ErrorCode == ErrorCode.Unavailable)
{
Console.WriteLine("FCM service is temporarily unavailable");
scheduleForRetryInAnHour();
}
else
{
Console.WriteLine($"Failed to send notification: {ex.Message}");
}
}
Accede a la respuesta HTTP
En algunos casos excepcionales, es posible que desees inspeccionar la respuesta de error de HTTP devuelta por un servicio de backend y realizar alguna acción de manejo de errores en él. El SDK de Admin Expone los encabezados y el contenido de estas respuestas de error. La respuesta contenido generalmente se devuelve como una cadena o una secuencia de bytes sin procesar, y se puede analizarse en cualquier formato de destino necesario.
Java
try {
FirebaseMessaging.getInstance().send(createMyMessage());
} catch (FirebaseMessagingException ex){
IncomingHttpResponse response = ex.getHttpResponse();
if (response != null) {
System.err.println("FCM service responded with HTTP " + response.getStatusCode());
Map<String, Object> headers = response.getHeaders();
for (Map.Entry<String, Object> entry : headers.entrySet()) {
System.err.println(">>> " + entry.getKey() + ": " + entry.getValue());
}
System.err.println(">>>");
System.err.println(">>> " + response.getContent());
}
}
Python
try:
messaging.send(create_my_message())
except exceptions.FirebaseError as ex:
response = ex.http_response
if response is not None:
print(f'FCM service responded with HTTP {response.status_code}')
for key, value in response.headers.items():
print(f'>>> {key}: {value}')
print('>>>')
print(f'>>> {response.content}')
Go
_, err := client.Send(ctx, createMyMessage())
if resp := errorutils.HTTPResponse(err); resp != nil {
log.Printf("FCM service responded with HTTP %d", resp.StatusCode)
for key, value := range resp.Header {
log.Printf(">>> %s: %v", key, value)
}
defer resp.Body.Close()
b, _ := ioutil.ReadAll(resp.Body)
log.Print(">>>")
log.Printf(">>> %s", string(b))
return
}
.Net
try
{
await FirebaseMessaging.DefaultInstance.SendAsync(createMyMessage());
}
catch (FirebaseMessagingException ex)
{
var response = ex.HttpResponse
if response != null
{
Console.WriteLine($"FCM service responded with HTTP { response.StatusCode}");
var headers = response.Headers;
for (var entry in response.Headers)
{
Console.WriteLine($">>> {entry.Key}: {entry.Value}");
}
var body = await response.Content.ReadAsString();
Console.WriteLine(">>>");
Console.WriteLine($">>> {body}");
}
}