【问题标题】:Spray request - Complete request only after nested futures喷涂请求 - 仅在嵌套期货后完成请求
【发布时间】:2015-02-01 14:07:19
【问题描述】:

spray 和 scala 的新手。这几天一直在努力让它正确。

我正在尝试将 facebook oauth2 登录 + 用户登录详细信息合并到数据库中,以防同一用户通过不同方式(用户/密码或 fb 登录)登录。

在喷涂路由sn-p下方粘贴。

  path("facebook") {
    post{
      entity(as[JObject]) { json =>
        val fb: FacebookAuthModel = json.extract[FacebookAuthModel]
        complete {

          //Get user details from fb oauth2
          val fbUser = fbAuth.getIdentity(fb) match {
            case Right(user: User) => user
            case Left(error: Failure) => throw new FailureException(error)
          }

          //Check if user is already present either by fb id or email
          val userFuture = userRepo(FetchUserByFacebook(fbUser.facebook.get,fbUser.email))

          userFuture.map {
            case u: User => {

              //user present but fb id not attached yet
              if (u.facebook.isEmpty) {
                //update fb id for the user - fire to actor and forget, i.e no callback to sender
                userRepo(UpdateFacebookId(u.id.get, fbUser.facebook.get))
              }

              //complete request with a token - request(1)
              AuthToken(token=jwt.createToken(u))
            }
            case None => {

              //first time user using fb login
              userRepo(CreateUser(fbUser)).map {

                //complete request with the token - request(2)
                case createdUser: User => AuthToken(token=jwt.createToken(createdUser))

                case None => throw new FailureException(Failure("Not able to CreateUser", FailureType.Unauthorized))
              }
            }
          }
        }  
      }
    }
  } 

除了第一次使用 fb 登录的用户外,一切正常(参考 request(2))。
在嵌套未来完成之前,请求以空响应完成。

我尝试对 userFuture 的结果进行平面映射,然后在其上使用 onComplete 以给出适当的响应,但它不起作用。

知道如何使用令牌成功完成请求(request(2))吗?

【问题讨论】:

    标签: scala akka spray spray-client


    【解决方案1】:

    如果代码执行路径中的两个分支之一可能导致Future,那么在处理userFuture 时,您必须将此编码为最低公分母。这意味着在userFuture 上使用flatMap 并在您没有​​明确的第二个Future 处理的情况下使用Future.successful。沿着这条线的东西:

    def handleUserResult(a:Any):Future[AuthToken] = a match{
      case u:User =>              
        if (u.facebook.isEmpty) {                
          userRepo(UpdateFacebookId(u.id.get, fbUser.facebook.get))
        }              
        Future.successful(AuthToken(token=jwt.createToken(u)))
    
      case None =>              
        userRepo(CreateUser(fbUser)).map {
          case createdUser: User =>
            AuthToken(token=jwt.createToken(createdUser))
    
          case None => 
            throw new FailureException(Failure("Not able to CreateUser", FailureType.Unauthorized))
        }
    }
    

    定义该方法后,您可以在userResult 上使用它,如下所示:

    userResult.flatMap(handleUserResult)
    

    我没有检查此代码是否存在编译问题。我更想展示flatMap 用于处理两种情况的一般方法,一种会产生另一种Future,另一种则不会。

    【讨论】:

    • 谢谢。这样可行。我确实尝试将 flatMapping Future[Future[User]] 映射到 Future[User] (并使用 Future.successful(user)) ,但是当我之前尝试过时,用这个结果未来变量做了一些愚蠢的事情来引发一些错误。
    猜你喜欢
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 2020-07-06
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    相关资源
    最近更新 更多