【问题标题】:Storing and sharing a cookie for service access in Scala在 Scala 中存储和共享用于服务访问的 cookie
【发布时间】:2023-05-01 20:56:01
【问题描述】:

我有一个 Scalatra 2.3 应用程序,它使用 Dispatch 联系旧服务以获取某些数据。一些 API 调用使用基于 cookie 的身份验证。我想避免为对这些安全端点的每个请求单独登录。

我的第一次尝试是一个伴生对象,它有一个 var for cookie 和一个函数 getCookie。这将从 var 返回存储的 cookie 或进行身份验证,将接收到的 cookie 存储到 var 并返回。如果 cookie 无效,逻辑将清除 cookie,检索它并重试调用。

object LegacyService {
  var cookie : Option[Cookie] = None

  def getCookie() :  Option[Cookie] = {
    this.synchronized {
    if (!cookie.isDefined) {
      def loginRequest = dispatch.url...

      val result = (for (r <- Http(loginRequest)) yield r.getCookies).apply()
      if (result.isEmpty) {
        cookie = None
      } else {
        cookie = Some(result.get(0))
      }
    }
    cookie
  }
}

在我对遗留服务执行多个需要 cookie 的并行异步调用之前,一切似乎都很好。出于某种原因,这导致了某种死锁,直到应用程序重新启动,所以在截止日期之前我最终把这个 cookie 存储代码扔掉了。

任何建议如何正确地做到这一点?

【问题讨论】:

    标签: scala cookies scalatra


    【解决方案1】:
    1. 我会尝试使用番石榴缓存来做这个 cookie 缓存

    https://code.google.com/p/guava-libraries/wiki/CachesExplained

        LoadingCache<Key, Cookie> graphs = CacheBuilder.newBuilder()
           .expireAfterAccess(10, TimeUnit.MINUTES)
           .build(
               new CacheLoader<Key, Cookie>() {
                 public Cookie load(Key key) { // no checked exception
                    def loginRequest = dispatch.url...
    
                    val result = (for (r <- Http(loginRequest)) yield r.getCookies).apply()
                    if (result.isEmpty) {
                        throw new RuntimeException();
                    }
    
                    return result.get(0)
                };
           });
    

    它可能会解决死锁问题,因为所有同步都将由 guava 处理。

    1. 另一种选择是使用一些 Scala 封装进行缓存,例如 mango(封装了番石榴缓存)

    https://github.com/feijoas/mango

    所以这看起来像:

    import org.feijoas.mango.common.base.Suppliers._
    
    // a supplier is just a function () => Cookie
    val supplier = () => getCookie ...          //> supplier  : () => Int 
                                                //= function0
    // convert to a Guava supplier
    val gSupplier = supplier.asJava             //> gSupplier  : com.google.common.base.Supplier[Cookie] 
                                                //= AsGuavaSupplier(function0)
    
    // create s supplier that memoize its return
    // value for 10 seconds
    val memSupplier = memoizeWithExpiration(supplier, 10, TimeUnit.SECONDS)
                                                  //> memSupplier  : () => Cookie  
                                                  //= Suppliers.memoizeWithExpiration(function0, 10, SECONDS)
    

    基本上,我想说的是,与其解决代码中的死锁问题,不如切换到常用的经过测试的 Cache 库,例如 guava,它不应该有任何并发​​问题。

    【讨论】:

      最近更新 更多