Yönetici SDK'sı hataları iki kategoriye ayrılır:
- Programlama hataları: Kullanıcı uygulamasındaki programlama ve konfigürasyon hatalarıdır. Çoğunlukla SDK'nın yanlış kullanımı (
null
değerleri kabul etmeyen bir yöntemenull
iletmek gibi) ve Firebase projesi veya SDK düzeyindeki diğer yapılandırma hataları (eksik kimlik bilgileri, hatalı proje kimliği dizesi vb.) nedeniyle oluşurlar. Açık). - API hataları: Bunlar, SDK uygulamasında meydana gelen çeşitli kurtarılabilir hataları, Firebase arka uç hizmetlerinden kaynaklanan tüm hataları ve RPC çağrıları yaparken oluşabilecek diğer geçici hataları (zaman aşımları gibi) içerir.
Admin SDK, söz konusu platforma özgü bir hata atarak programlama hatalarını bildirir.
- Java:
IllegalArgumentException
,NullPointerException
veya benzeri yerleşik çalışma zamanı hata türünün örneklerini atar. - Python:
ValueError
,TypeError
veya diğer yerleşik hata türünün örneklerini yükseltir. - Git: Genel bir hata döndürür.
- .NET:
ArgumentException
,ArgumentNullException
veya benzer yerleşik hata türünün örneklerini atar.
Çoğu durumda programlama hatalarını açıkça ele almamalısınız. Bunun yerine, programlama hatalarını tamamen önlemek için kodunuzu ve yapılandırmanızı düzeltmelisiniz. Aşağıdaki Java pasajını göz önünde bulundurun:
String uid = getUserInput();
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
getUserInput()
yöntemi null
veya boş dizeler döndürürse FirebaseAuth.getUser()
API, bir IllegalArgumentException
oluşturur. Bunu açıkça ele almak yerine getUserInput()
yönteminin hiçbir zaman geçersiz bir UID dizesi döndürmemesini sağlayarak sorunu hafifletebilirsiniz. Bu mümkün değilse, gerekli argüman kontrolünü kendi kodunuzda aşağıdaki gibi uygulayın:
String uid = getUserInput();
if (Strings.isNullOrEmpty(uid)) {
log.warn("UID must not be null or empty");
return;
}
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
Prensip olarak programlama hatalarını asla tekrar denemeyin. Programlama hatalarında hızlı anlambilime izin vermek çoğu zaman en iyi eylem yöntemidir çünkü geliştirme sırasında programlama hatalarını ve yapılandırma hatalarını ortaya çıkarır ve bunların derhal düzeltilebilmesini sağlar. Bu bağlamda hızlı hata, hataların uygulamanızdaki genel hata işleyicisine yayılmasına izin vermek veya bunları yalnızca denetim amacıyla günlüğe kaydetmek ve ardından mevcut yürütme akışının sonlandırılması anlamına gelebilir (uygulamanın çökmesine gerek olmamalıdır). Genel olarak, programlama diliniz ve uygulama çerçeveniz için en iyi hata giderme uygulamalarını takip edin. Bu tek başına genellikle bu tür hatalarla doğru şekilde başa çıkmak için yeterlidir.
Genellikle hata işleme çabalarınızın büyük kısmı API hatalarını ele almaya odaklanacaktır. Geçici olarak kullanılamayan bir hizmetten kaynaklanan hatalar gibi bu hataların bazıları kurtarılabilir niteliktedir ve bazıları, geçersiz veya süresi dolmuş kimlik belirteçlerinin tespit edilmesi gibi normal program yürütme akışı sırasında bile tahmin edilebilir. Bu kılavuzun geri kalanında Admin SDK'nın bu tür API hatalarını nasıl temsil ettiği ve bunları işlemek için kullanılabilen çeşitli seçenekler özetlenmektedir.
API hatasının yapısı
Bir API hatası aşağıdaki bileşenlerden oluşur:
- Hata kodu
- Hata mesajı
- Servis hata kodu (İsteğe bağlı)
- HTTP yanıtı (İsteğe bağlı)
Her API hatasının bir hata kodu ve bir hata mesajı içermesi garanti edilir. Bazı API hataları, hatayı oluşturan API'ye özel bir hizmet hata kodu da içerir. Örneğin, Firebase Auth API tarafından oluşturulan bazı hatalar, Firebase Auth'a özel bir hizmet hata kodu içerir. Hata, bir arka uç hizmetinden gelen bir HTTP hata yanıtının sonucuysa, API hatası aynı zamanda karşılık gelen HTTP yanıtını da içerir. Bu, orijinal yanıtın tam başlıklarını ve içeriğini incelemek için kullanılabilir; bu, hata ayıklama, günlüğe kaydetme veya daha karmaşık hata işleme mantığının uygulanması için faydalıdır.
Node.js dışındaki tüm Admin SDK uygulamaları, yukarıdaki API hata bileşenlerine erişime olanak tanıyan API'ler sağlar.
Dile göre hata türleri ve API'ler
Java
Java'da tüm API hataları FirebaseException
sınıfını genişletir. Bu temel sınıftan hata koduna, hata mesajına ve isteğe bağlı HTTP yanıtına erişebilirsiniz.
public class FirebaseException extends Exception {
@NonNull
public ErrorCode getErrorCode() {
// ...
}
@NonNull
public String getMessage() {
// ...
}
@Nullable
public IncomingHttpResponse getHttpResponse() {
// ...
}
}
Hizmet hata kodlarını açığa çıkaran API'ler, FirebaseException
öğesinin API'ye özgü alt sınıflarını sağlar. Örneğin, FirebaseAuth
API'sindeki tüm genel yöntemlerin FirebaseAuthException
örneklerini oluşturacağı bildirildi. Servis hata koduna bu türetilmiş sınıftan ulaşabilirsiniz.
public class FirebaseAuthException extends FirebaseException {
@Nullable
public AuthErrorCode getAuthErrorCode() {
// ...
}
}
Python
Python'da tüm API hataları, exceptions.FirebaseError
sınıfını genişletir. Bu temel sınıftan hata koduna, hata mesajına ve isteğe bağlı HTTP yanıtına erişebilirsiniz.
class FirebaseError(Exception):
@property
def code(self):
# ...
@property
def message(self):
# ...
@property
def http_response(self):
# ...
Ayrıca Python Admin SDK, her hata kodu için ayrı türetilmiş sınıflar sunar. Bunları platform hata sınıfları olarak adlandırıyoruz.
class InvalidArgumentError(FirebaseError):
# ...
class NotFoundError(FirebaseError):
# ...
Kodunuzda FirebaseError
yakalayıp code
kontrol edebilir veya bir platform hata sınıfına karşı isinstance()
kontrolü gerçekleştirebilirsiniz. Veya belirli platform hata türlerini doğrudan yakalamak için kod yazabilirsiniz. İkinci yaklaşımın daha okunabilir hata işleme koduyla sonuçlanması muhtemeldir.
Hizmet hata kodlarını açığa çıkaran API'ler, platform hata sınıflarının API'ye özgü alt sınıflarını sağlar. Örneğin, auth
modülündeki tüm genel yöntemler, auth.UserNotFoundError
ve auth.ExpiredIdTokenError
gibi API'ye özgü hata türlerini atabilir.
class UserNotFoundError(exceptions.NotFoundError):
# …
class ExpiredIdTokenError(exceptions.InvalidArgumentError):
# ...
Gitmek
Go Admin SDK, hata kodlarının test edilmesine olanak tanıyan bir dizi işlevi içeren bir errorutils
paketi sağlar.
package errorutils
func IsInvalidArgument(err error) bool {
// ...
}
func IsNotFound(err error) bool {
// ...
}
Hata mesajı, bir hatanın Error()
işlevi tarafından döndürülen dizedir. İsteğe bağlı HTTP yanıtına, *http.Response
değerini döndüren errorutils.HTTPResponse()
işlevi çağrılarak erişilebilir.
errorutils
paketindeki hata kontrol işlevlerine nil
veya başka bir hata değeri iletmek güvenlidir. Giriş argümanı gerçekten söz konusu hata kodunu içeriyorsa true
döndürürler ve diğer her şey için false
değerini döndürürler. HTTPResponse()
işlevi, false
yerine nil
değerini döndürmesi dışında benzer davranışa sahiptir.
Hizmet hata kodlarını açığa çıkaran API'ler, ilgili paketlerde API'ye özgü hata denetimi işlevleri sağlar. Örneğin, auth
paketi IsUserNotFound()
ve IsExpiredIDTokenError()
işlevlerini sağlar.
.AÇIK
.NET'te tüm API hataları FirebaseException
sınıfını genişletir. Bu temel sınıftan platform hata koduna, hata mesajına ve isteğe bağlı HTTP yanıtına erişebilirsiniz.
public class FirebaseException : Exception {
public ErrorCode ErrorCode { get; }
public String Message { get; }
public HttpResponseMessage HttpResponse { get; }
}
Hizmet hata kodlarını açığa çıkaran API'ler, FirebaseException
öğesinin API'ye özgü alt sınıflarını sağlar. Örneğin, FirebaseAuth
API'sindeki tüm genel yöntemlerin FirebaseAuthException
örneklerini oluşturacağı bildirildi. Servis hata koduna bu türetilmiş sınıftan ulaşabilirsiniz.
public class FirebaseAuthException : FirebaseException {
public AuthErrorCode AuthErrorCode { get; }
}
Platform hata kodları
Hata kodları tüm Firebase ve Google Cloud Platform hizmetlerinde ortaktır. Aşağıdaki tablo tüm olası platform hata kodlarını özetlemektedir. Bu istikrarlı bir listedir ve uzun süre değişmeden kalması beklenmektedir.
GEÇERSİZ ARGÜMAN | Müşteri geçersiz bir bağımsız değişken belirtti. |
FAILED_PRECONDITION | Boş olmayan bir dizinin silinmesi gibi mevcut sistem durumunda istek yürütülemez. |
OUT_OF_RANGE | İstemci geçersiz bir aralık belirtti. |
DOĞRULANMAMIŞ | Eksik, geçersiz veya süresi dolmuş OAuth jetonu nedeniyle isteğin kimliği doğrulanamadı. |
İZİN REDDEDİLDİ | İstemcinin yeterli izni yok. Bunun nedeni OAuth belirtecinin doğru kapsamlara sahip olmaması, istemcinin izne sahip olmaması veya API'nin istemci projesi için etkinleştirilmemiş olmasıdır. |
BULUNAMADI | Belirtilen kaynak bulunamadı veya beyaz listeye alınma gibi açıklanmayan nedenlerden dolayı istek reddedildi. |
ANLAŞMAZLIK | Okuma-değiştirme-yazma çakışması gibi eşzamanlılık çakışması. Yalnızca birkaç eski hizmet tarafından kullanılır. Çoğu hizmet bunun yerine ABORTED veya ALREADY_EXISTS kullanır. Kodunuzda hangisinin işleneceğini görmek için hizmete özel belgelere bakın. |
DURDURULDU | Okuma-değiştirme-yazma çakışması gibi eşzamanlılık çakışması. |
ZATEN VAR | Bir istemcinin oluşturmaya çalıştığı kaynak zaten mevcut. |
RESOURCE_EXHAUSTED | Kaynak kotası bitti veya oran sınırlamasına ulaşıldı. |
İPTAL EDİLDİ | İstek müşteri tarafından iptal edildi. |
VERİ KAYBI | Kurtarılamaz veri kaybı veya veri bozulması. İstemci hatayı kullanıcıya bildirmelidir. |
BİLİNMEYEN | Bilinmeyen sunucu hatası. Genellikle bir sunucu hatası. Bu hata kodu aynı zamanda yerel yanıt ayrıştırma (normal olmayan) hatalarına ve kolayca teşhis edilemeyen çok çeşitli diğer düşük seviyeli G/Ç hatalarına da atanır. |
DAHİLİ | İç Sunucu Hatası. Genellikle bir sunucu hatası. |
KULLANIM DIŞI | Hizmet kullanılamıyor. Genellikle sunucu geçici olarak kapalıdır. Bu hata kodu aynı zamanda yerel ağ hatalarına da atanır (bağlantı reddedildi, ana bilgisayara rota yok). |
DEADLINE_EXCEEDED | Talep süresi aşıldı. Bu, yalnızca arayan kişinin hedef API'nin varsayılan son tarihinden daha kısa bir son tarih belirlemesi durumunda (yani talep edilen son tarih, sunucunun isteği işlemesi için yeterli değilse) ve isteğin son tarih içinde tamamlanmaması durumunda gerçekleşir. Bu hata kodu aynı zamanda yerel bağlantıya ve okuma zaman aşımlarına da atanır. |
Çoğu API, yukarıdaki hata kodlarının yalnızca bir alt kümesiyle sonuçlanabilir. Her durumda, hata işleyicilerinizi uygularken tüm bu hata kodlarını açıkça işlemeniz beklenmez. Çoğu uygulama yalnızca 1-2 spesifik hata koduyla ilgilenir ve geri kalan her şeyi genel, kurtarılamaz bir arıza olarak ele alır.
Hizmete özel hata kodları
Firebase Yetkilendirmesi
CERTIFICATE_FETCH_FAILED | Bir JWT'yi (kimlik belirteci veya oturum çerezi) doğrulamak için gereken ortak anahtar sertifikaları getirilemedi. |
BU E-POSTA ZATEN VAR | Sağlanan e-postaya sahip bir kullanıcı zaten mevcut. |
EXPIRED_ID_TOKEN | verifyIdToken() için belirtilen kimlik belirtecinin süresi doldu. |
EXPIRED_SESSION_COOKIE | verifySessionCookie() iis için belirtilen oturum çerezinin süresi doldu. |
INVALID_DYNAMIC_LINK_DOMAIN | Sağlanan dinamik bağlantı etki alanı, mevcut proje için yapılandırılmamış veya yetkilendirilmemiş. E-posta eylem bağlantısı API'leriyle ilgilidir. |
INVALID_ID_TOKEN | verifyIdToken() için belirtilen kimlik belirteci geçersiz. |
INVALID_SESSION_COOKIE | verifySessionCookie() için belirtilen oturum çerezi geçersiz. |
PHONE_NUMBER_ALREADY_EXISTS | Sağlanan telefon numarasına sahip bir kullanıcı zaten mevcut. |
REVOKED_ID_TOKEN | verifyIdToken() için belirtilen kimlik belirteci iptal edildi. |
REVOKED_SESSION_COOKIE | verifySessionCookie() için belirtilen oturum çerezinin süresi doldu. |
UNAUTHORIZED_CONTINUE_URL | Devam URL'sinin alanı beyaz listede değil. E-posta eylem bağlantısı API'leriyle ilgilidir. |
KULLANICI BULUNAMADI | Verilen tanımlayıcı için kullanıcı kaydı bulunamadı. |
Firebase Bulut Mesajlaşma
THIRD_PARTY_AUTH_ERROR | APN sertifikası veya web push kimlik doğrulama API anahtarı geçersiz veya eksikti. |
GEÇERSİZ ARGÜMAN | İstekte belirtilen bir veya daha fazla bağımsız değişken geçersizdi. |
DAHİLİ | İç Sunucu Hatası. |
KOTA AŞILDI | İleti hedefi için gönderme sınırı aşıldı. |
SENDER_ID_MISMATCH | Kimliği doğrulanmış gönderen kimliği, kayıt jetonunun gönderen kimliğinden farklıdır. Bu genellikle gönderenin ve hedef kayıt jetonunun aynı Firebase projesinde olmadığı anlamına gelir. |
KULLANIM DIŞI | Bulut Mesajlaşma hizmeti geçici olarak kullanılamıyor. |
KAYITSIZ | Uygulama örneğinin FCM'deki kaydı kaldırıldı. Bu genellikle kullanılan cihaz kayıt jetonunun artık geçerli olmadığı ve yenisinin kullanılması gerektiği anlamına gelir. |
Otomatik yeniden denemeler
Admin SDK, belirli hataları kullanıcılara göstermeden önce otomatik olarak yeniden dener. Genel olarak aşağıdaki hata türleri şeffaf bir şekilde yeniden denenir:
- HTTP 503 (Hizmet Kullanılamıyor) yanıtlarından kaynaklanan tüm API hataları.
- HTTP 500 (Dahili Sunucu Hatası) yanıtlarından kaynaklanan bazı API hataları.
- Çoğu düşük seviyeli G/Ç hatası (bağlantı reddedildi, bağlantı sıfırlandı vb.).
SDK, yukarıdaki hataların her birini üstel geri çekilmeyle en fazla 5 defa (orijinal deneme + 4 yeniden deneme) yeniden deneyecektir. İsterseniz uygulama düzeyinde kendi yeniden deneme mekanizmalarınızı uygulayabilirsiniz, ancak bu genellikle gerekli değildir.
Yeniden Dene-Sonra desteği
Admin SDK'nın Go ve .NET uygulamaları, HTTP Retry-After
başlığını işleme desteğiyle birlikte gelir. Yani, arka uç sunucuları tarafından gönderilen hata yanıtı standart Retry-After
başlığını içeriyorsa, SDK, belirtilen bekleme süresi çok uzun olmadığı sürece yeniden deneme sırasında buna saygı gösterecektir. Retry-After
başlığı çok uzun bir bekleme süresi gösteriyorsa SDK, yeniden denemeleri atlayacak ve uygun API hatasını verecektir.
Python Admin SDK şu anda Retry-After
başlığını desteklemiyor ve yalnızca basit üstel geri çekilmeyi destekliyor.
API hata işleme örnekleri
Genel bir hata işleyicisinin uygulanması
Çoğu durumda istediğiniz şey, bir API hatası nedeniyle program akışının beklenmeyen şekilde sonlandırılmasını önlemek için geniş bir hata aralığını yakalayan genel bir hata işleyicisidir. Bu tür hata işleyicileri genellikle hataları yalnızca denetim amacıyla günlüğe kaydeder veya karşılaşılan tüm API hataları için başka bir varsayılan hata işleme rutinini çağırır. Farklı hata kodlarıyla veya hataya neden olabilecek nedenlerle ilgilenmeleri gerekmez.
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}')
Gitmek
token, err := client.VerifyIDToken(ctx, idToken)
if err != nil {
log.Printf("Failed to verify ID token: %v", err)
return
}
performPrivilegedOperation(token)
.Açık
try
{
var token = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
PerformPrivilegedOperation(token.getUid());
}
catch (FirebaseAuthException ex)
{
Conole.WriteLine($"Failed to verify ID token: {ex.Message}");
}
Hata kodlarının kontrol edilmesi
Bazı durumlarda, tam hata kodlarını incelemek ve farklı bağlama duyarlı hata işleme rutinlerini başlatmak isteyebilirsiniz. Aşağıdaki örnekte, hizmet hata koduna göre daha spesifik hata mesajlarını günlüğe kaydeden bir hata işleyicimiz var.
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}')
Gitmek
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)
.Açık
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}");
}
}
Hem üst düzey hem de hizmet hata kodlarını kontrol ettiğimiz başka bir örneği burada bulabilirsiniz:
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}')
Gitmek
_, 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
}
.Açık
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}");
}
}
HTTP yanıtına erişme
Bazı nadir durumlarda, bir arka uç hizmeti tarafından döndürülen HTTP hata yanıtını incelemek ve üzerinde bazı hata işleme eylemleri gerçekleştirmek isteyebilirsiniz. Admin SDK, bu hata yanıtlarının hem başlıklarını hem de içeriğini gösterir. Yanıt içeriği genellikle bir dize veya ham bayt dizisi olarak döndürülür ve gereken herhangi bir hedef formatta ayrıştırılabilir.
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}')
Gitmek
_, 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
}
.Açık
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}");
}
}