3

我使用Ionic2Angularfire2访问Firebase AuthenticationFirebase如何取消订阅

我访问以下rxjs/Observable

chats.ts

this.firelist = this.dataService.findChats(); 
    this.subscription = this.firelist.subscribe(chatItems => { 
    ... 
    }); 

    ngDestroy() { 
    this.subscription.unsubscribe(); 
    } 

dataService.ts

findChats(): Observable<any[]> { 
     this.firebaseDataService.findChats().forEach(firebaseItems => { 
      ... 
      observer.next(mergedItems); 
     }); 
} 

firebaseDataService.ts

findChats(): Observable<any[]> { // populates the firelist 
    return this.af.database.list('/chat/', { 
     query: { 
      orderByChild: 'negativtimestamp' 
     } 
    }).map(items => { 
     const filtered = items.filter(
      item => (item.memberId1 === this.me.uid || item.memberId2 === this.me.uid) 
     ); 
     return filtered; 
    }); 
} 

另外,在火力地堡认证,我有以下实时数据库规则:

"rules": { 
     ".read": "auth != null", 
     ".write": "auth != null", 
    } 

问题

这工作完全在用户已登录(即auth != null),但只要用户注销,并auth == null,我收到以下错误:

ERROR Error: Uncaught (in promise): Error: permission_denied at /chat: Client doesn't have permission to access the desired data. Error: permission_denied at /chat: Client doesn't have permission to access the desired data.

问题

正如你可以在上面的代码中看到,我尝试unsubscribe从Firebase身份验证服务,但必须做到不正确。如果有人可以建议我应该如何阻止我的应用查询Firebase数据库unsubscribe,我将不胜感激。

+0

你为什么不''this.firelist.unsubscribe()' – Skeptor

+0

嗨Skeptor,感谢您的反馈。 'this.firelist'是一个'rxjs/Observable ',并且api没有'unsubscribe'功能。但是,它返回一个'订阅',确实有一个,所以这是我没有成功地尝试,如上所示。 http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html – Richard

+0

我从不取消订阅,所以不确定语法。但在我看来,你需要为每个http调用观看auth对象状态,而不是取消订阅。我将提供一种不同的方式来编写相同的代码,以及我在应用程序中的做法。 (我使用aws,但它们几乎相同) – Skeptor

回答

1

这不是问题的确切答案,但我的观点是,如果我们以其他方式这样做,我们将永远不会遇到这个问题。

P.S:我从来没有使用firebase,我使用AWS,因此firebase代码可能不准确,我们将讨论它。

这里是我的版本:

findChats(): Observable<any[]> { // populates the firelist 
    return 
     this.authService.getCurrentUser() 
     .flatMap(user => user === null ? 
      Observable.empty():   
      this.af.database.list('/chat/', { 
      query: { 
       orderByChild: 'negativtimestamp' 
      } 
      }) 
      .map(items => 
      return items.filter(
       item => (
        item.memberId1 === this.me.uid || 
        item.memberId2 === this.me.uid 
       ) 
      ) 
     ) 
    ); 
} 

验证服务

public currentUser = new BehaviorSubject(null); 

constructor(){ 

    firebase.auth().onAuthStateChanged(function(user) { 
     if (user) { 
      // User is signed in. 
      currentUser.next(user); 
     } else { 
     // No user is signed in. 
      currentUser.next(null); 
     } 
    }); 

}  

的代码非常原始,但我希望它传达的理念。在这里我正在观察用户身份验证状态并执行flatMap来获取数据。如果用户注销,则认证状态更改为空,因此在UI中数据更改为空列表。即使用户没有注销,他仍然无法看到数据。


UPDATE

重构对方回答:

findChats(){ 
    return Observable.merge(
     this.firebaseDataService 
      .findChats() 
      .flatMap(chats => Observable.from(chats)), 
     this.localDataService 
      .findChats() 
      .flatMap(chats => Observable.from(chats)) 
    ) 
    .filter(chat => !!chat) 
    .toArray() 
    .map(chats => [ 
     ...chats.sort(
     (a, b) => 
      parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp)) 
     ] 
    ); 
} 

除非你正在使用Subject缓存响应从不使用subscribe内的服务。

0

unsubscribe工作正常。这个问题原来,下面的函数我用过,导致它由于某种原因,订阅两次:

findChats(): Observable<any[]> { 
    return Observable.create((observer) => { 
     this.chatSubscription2 = this.firebaseDataService.findChats().subscribe(firebaseItems => { 
      this.localDataService.findChats().then((localItems: any[]) => { 
       let mergedItems: any[] = []; 
       if (localItems && localItems != null && firebaseItems && firebaseItems != null) { 
        for (let i: number = 0; i < localItems.length; i++) { 
         if (localItems[i] === null) { 
          localItems.splice(i, 1); 
         } 
        } 
        mergedItems = this.arrayUnique(firebaseItems.concat(localItems), true); 
       } else if (firebaseItems && firebaseItems != null) { 
        mergedItems = firebaseItems; 
       } else if (localItems && localItems != null) { 
        mergedItems = localItems; 
       } 
       mergedItems.sort((a, b) => { 
        return parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp); 
       }); 
       observer.next(mergedItems); 
       this.checkChats(firebaseItems, localItems); 
      }); 
     }); 
    }); 
} 

出于某种原因,第3行以上的被称为两次(即使该功能只调用一次)。这是创建第二个subscription,而第一个subscription从来没有unsubscribed

因此看起来Observable的创建不正确。我不确定是什么,但创建Observable的正确方法。

+0

我发布了一个关于如何创建'Observable'的问题,以便这里只有一个订阅: https://stackoverflow.com/questions/44883886/observable-create-is-called-twice – Richard

+0

你不应该使用'Observable.create'。在使用map进行一些转换之后直接返回'this.firebaseDataService'。 – Skeptor

+0

我不知道该怎么做,因为使用'Observable'的列表当前正在订阅它,即它需要动态更新。 – Richard