0

Scala と Play 2.5.10 を使用して、構成用に次の再利用可能なアクションを実装し、応答ヘッダーを変更してブラウザーでのキャッシュを無効にすることを目的としました。

import play.api.http.HeaderNames
import play.api.mvc._

import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global

case class NoCache[A](action: Action[A]) extends Action[A] with HeaderNames {
  def apply(request: Request[A]): Future[Result] = {
    action(request).andThen {
      case Success(result) => result.withHeaders(
        (CACHE_CONTROL -> "no-cache, no-store, must-revalidate"),
        (PRAGMA -> "no-cache"),
        (EXPIRES -> "0")
      )
      case Failure(result) => result
    }
  }

  lazy val parser = action.parser
}

次に、コントローラー アクションの実装で次のように再利用します。

def link = NoCache {
  deadbolt.SubjectPresent()() { implicit request =>
    Future {
      Ok(views.html.account.link(userService, auth))
    }
  }
}

実装にブレークポイントを設定するNoCacheと、正しく実行されますが、Web Developer Firefox プラグインを使用してネットワーク トラフィックを監視すると、応答ヘッダーに「キャッシュなし」の変更が含まれていないことがわかります...何が間違っていますか?

4

1 に答える 1

1

コードの問題

問題はandThen. andThen戻り値を破棄します。そのため、新しいヘッダーで変換さresultれたものは破棄されています。

削除andThenして にしmapます。

andThen呼び出された Future の完了直後に副作用計算を実行するために使用されます。

の計算はandThen、元の future と同じ結果を持つ Future を返し、 内の計算の戻り値の型を破棄しandThenます。

andThen標準ライブラリからの実装です。

 def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = {
    val p = Promise[T]()
    onComplete {
      case r => try pf.applyOrElse[Try[T], Any](r, Predef.conforms[Try[T]]) finally p complete r
    }
    p.future
  }

コードを修正する

case class NoCache[A](action: Action[A]) extends Action[A] with HeaderNames {
  def apply(request: Request[A]): Future[Result] = {
    action(request).map { result =>
      result.withHeaders(
        (CACHE_CONTROL -> "no-cache, no-store, must-revalidate"),
        (PRAGMA -> "no-cache"),
        (EXPIRES -> "0")
      )
    }
  }

  lazy val parser = action.parser
}

同じことを行う他の方法

Play フィルターFilterを使用してヘッダーを変更したり、前処理および後処理作業を実行したりするために使用することもできます。

リクエストの uri を確認することで、特定のルートのみをターゲットにすることができます。

import akka.stream.Materializer
import com.google.inject.{Inject, Singleton}
import play.api.http.DefaultHttpFilters
import play.api.mvc.{Filter, RequestHeader, Result}
import play.mvc.Http.HeaderNames

import scala.concurrent.Future

@Singleton
class Filters @Inject() (fooFilter: FooFilter) extends DefaultHttpFilters(fooFilter) {}

@Singleton
class FooFilter @Inject() (implicit override val mat: Materializer) extends Filter {
  override def apply(f: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = {
    f(rh).map { result =>
      if (rh.uri.startsWith("/foo"))
      result.withHeaders(HeaderNames.CACHE_CONTROL -> "no-cache")
      else result
    }
  }
}

上記の/fooルートの例では、cache_control が設定され、他のルートでは同じヘッダーが伝播されます。

application.conf にフィルターを追加していない場合は、play アプリのルート フォルダー内にフィルターを作成することに注意してください。

フィルター内で重い計算を実行しないでください。フィルターをできるだけ軽くしてください。

于 2016-12-26T11:25:23.873 に答える