Arhn - архитектура программирования

Как передать переменную в действие из перехваченного запроса в PlayFramework?

Я перехватываю все запросы к моему игровому приложению, переопределяя метод onRouteRequest GlobalSettings. Теперь мне нужно отправить некоторые данные в отправленное действие отсюда, чтобы я не выполнял все эти вычисления во всех действиях. Как установить атрибут объекта запроса (play.api.mvc.RequestHeader), который я передаю методу super onRouteRequest?


  • Установка атрибута недоступна, потому что в функциональном плане мы находимся в неизменяемой среде. Так что, например, при добавлении материала в сеанс вы создаете новый с помощью withSession. И в контексте onRouteRequest вы не можете создать новый запрос, потому что вы не сможете передать это новое вашему базовому действию. 10.06.2012
  • +100, та же лодка, есть фрагмент данных для вставки в запрос, который применяется ко ВСЕМ маршрутам/типам действий. Я хотел бы выполнить расчет данных в одном месте, onRouteRequest, а затем в любом месте приложения, где неявный запрос находится в области действия, иметь доступ к данным (вместо повторного расчета в разных местах или добавление шаблона для каждого действия для его обработки). 28.10.2012
  • @andypetrella scala не является чисто функциональной. Мы можем вводить данные в композицию «Запрос через действие» и WrappedRequest, эффективно изменяя пост-маршрут запроса. Мне бы очень хотелось установить заполнитель Map[String,String] в onRouteRequest. Вы можете скопировать запрос и, например, присвоить значение тегам Map в RequestHeader. Играйте, конечно, сдувая ваши драгоценные данные, используя теги Map для маршрутизации результатов (метод контроллера, тип GET и т.д.) 28.10.2012
  • @virtualeyes, ты прав, Scala — это не только f°. Однако ядро ​​​​Play использует максимум функциональные парадигмы, чтобы упростить параллелизм и так далее. Вот почему такие вещи неизменяемы в Play. Тем не менее, я не понимаю вашу точку зрения? Что бы Вы хотели? Модификация на месте? 29.10.2012
  • WrappedRequest — это единственный способ, на самом деле, имитировать ввод данных в запрос. Это работает, и работает довольно хорошо, просто пришлось реорганизовать мое действие Authenticate, чтобы расширить новую черту действия Task, которая сопоставляет класс case с желаемыми параметрами с WrappedRequest. Затем в любом месте приложения вместо ссылки на play.api.mvc.Request вы ссылаетесь на com.company.Task, который содержит идентификатор сеанса пользователя и данные, извлеченные/преобразованные из URI. 29.10.2012

Ответы:


1

Для ваших нужд я не думаю, что использование onRouteRequest будет работать (по крайней мере, элегантно).

Но давайте попробуем использовать специальную структуру для перехвата.

Вот как вы можете перехватить запрос, вычислить некоторые общие данные и передать их в действие.

Во-первых, вот объект Interceptor, у которого есть метод intercept и удобный метод username:

object Interceptor {

  def intercept[A, B](f: RequestHeader => Option[B], e: RequestHeader => Result)(action: B => Action[A]): Action[(Action[A], A)] = {

    val bodyParser = BodyParser {
      request =>
        f(request) map {
          b =>
            val innerAction = action(b)
            innerAction.parser(request).mapDone {
              body => body.right.map(innerBody => (innerAction, innerBody))
            }
        } getOrElse {
          Done(Left(e(request)), Input.Empty)
        }
    }

    Action(bodyParser) {
      request =>
        val (innerAction, innerBody) = request.body
        innerAction(request.map(_ => innerBody))
    }
  }

  def username[A](check: RequestHeader => Option[String]): ((String) => Action[A]) => Action[(Action[A], A)] = intercept(check, r => Results.Unauthorized("not logged in"))

}

Как видите, рабочая функция intercept дает вам возможность вычислить некоторые вещи на основе содержимого запроса. Какой результат вычисления типа B может быть неудачным (Option), в этом случае обработчик должен сказать, что делать.

Определив, что вычислять, вы можете определить action с помощью функции, которая принимает B и возвращает Action[A].

Метод username — это просто простой предопределенный перехватчик, который позволяет нам определить, как получить имя пользователя, вошедшего в систему, просто для иллюстрации.

Теперь вот как мы можем использовать их оба в вашем Controller

  //index is defined for both GET and POST in routes, but fails on POST
  //  thanks to the interceptor that checks at first the used method
  //  the case mustn't be handled in the Action definition
  def index = Interceptor.intercept(
    /*check the method*/
    request => if (request.method == "GET") Some(request.method) else None,

    /*not a GET => bad request*/
    request => BadRequest(request.method + " not allowed")

  ) { /*the computation result*/method => Action {
      Ok("The method : " + method)
    }
  }

  //this controller retrieve the username in the session and renders it in a OK response
  def secured = Interceptor.username(r => r.session.get("username")) { username => Action {
      Ok("You're logged in as " + username)
    }
  }

  //this enables you to logged in => store in session
  def login(u:String) = Action { request => {
      Ok("Logged in as " + u) withSession(("username" -> u))
    }
  }

Теперь, если у вас есть общие вычисления, вы можете создать свой предварительно сконфигурированный перехватчик (здесь я использую класс case, но достаточно просто определить функцию, которая частично применяет interceptor)

  case class Intercept[B] (f: RequestHeader => Option[B], e: RequestHeader => Result) {

    def apply[A](action: B => Action[A]) = Interceptor.intercept[A,B](f, e)(action)

  }


  val getInterceptor = Intercept[String](
    request => if (request.method == "GET") Some(request.method) else None,
    request => BadRequest(request.method + " not allowed")
  )


  def index2 = getInterceptor { method => Action {
      Ok("Da method : " + method)
    }
  }

EDIT в отношении комментария:

Согласно вашему комментарию, вот как вы могли бы использовать перехватчик (обратите внимание, что я смоделировал поиск и проверку хоста)

Используя hosted и anotherHosted, вы сможете протестировать этот рабочий процесс:

  • /hosted/false?host=myhost => 404, потому что сначала myhost не кэшируется, и я предоставил false проверенному макету
  • /hosted/true?host=myhost => не в кеше, но добавит, а потом нет 404
  • /hosted/anotherHosted/false?host=myhost => в кеше, потому что он размещен => нет 404
  • /hosted/anotherHosted/false?host=notMyhost => 404

Вот код

def getHost(request:RequestHeader) = request.queryString.get("host").get.head
def checkHost(host:String, b: Boolean) = b

val checkHosted = (b: Boolean) => Intercept[String](
  request => {
    val host = getHost(request)
    Cache.getAs[String](host) match {
      case x@Some(_) => x
      case None => if (checkHost(host, b)) {
        Cache.set(host, host)
        Some(host)
      } else None
    }

  },
  request => NotFound(getHost(request) + "not hosted")
)

def hosted(b:String) = checkHosted(b.toBoolean) {
  host => Action {
    Ok("this host is ok : " + host)
  }
}
def anotherHosted(b:String) = checkHosted(b.toBoolean) {
  host => Action {
    Ok("this host is ok : " + host)
  }
}
10.06.2012
  • Спасибо, Энди. Позвольте мне рассказать вам точный сценарий. Я создаю размещенное приложение, в котором пользователи могут зарегистрироваться и сопоставить свой домен. Когда их пользователи/клиенты обращаются к своему сопоставленному домену, он сначала проверяет, размещен ли домен у нас, или возвращает ошибку 404. Если домен размещен, я хочу передать информацию о сайте всем действиям, чтобы я не получал ее снова в них. 10.06.2012
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..