Как составить пользовательскую композицию действий для регистрации запроса и ответа в Play 2.3?

Я работаю над приложением Play 2.3 (Java), и мне нужна пользовательская композиция действий для регистрации запроса и ответа. С тем, что у меня есть, я могу получить тело запроса, но не ответ:

import play.libs.F;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;

public class LogAction extends Action.Simple {

    public F.Promise<Result> call(Http.Context ctx) throws Throwable {
        //Request body
        String requestBody = ctx.request().body().asText();
        //Need to get response body here
        //String responseBody = ???
        return delegate.call(ctx);
    }

}

Как получить тело ответа в этом сценарии? Если это сложно сделать в java, это может быть и в scala, однако он должен работать с аннотацией метода @With java-контроллера.


person Caballero    schedule 02.10.2014    source источник


Ответы (2)


    @Override
    public F.Promise<Result> call(Http.Context ctx) throws Throwable {
        Promise<Result> call = delegate.call(ctx);
        return call.map((r) -> {
            byte[] body = JavaResultExtractor.getBody(r, 0l);
            Logger.info(new String(body));
            return r;
        });
    }

Вы можете использовать play.core.j.JavaResultExtractor для извлечения тела из ответа. Имейте в виду, что getBody(..) блокируется до тех пор, пока ответ не будет готов, поэтому рассмотрите возможность вызова onRedeem вместо map.

person Mon Calamari    schedule 03.10.2014
comment
JavaResultExtractor.getBody (результат, 0L) дает тайм-аут, даже если я изменю его с 0 на 100k. - person Sanjeev Kumar Dangi; 29.09.2016

Вы пробовали что-то вроде этого:

public class VerboseAction extends play.mvc.Action.Simple {

    public F.Promise<Result> call(Http.Context ctx) throws Throwable {
        Logger.info("Calling action for " + ctx);
        F.Promise<Result> resultPromise = delegate.call(ctx);
        resultPromise.map(result -> {
            Logger.info(result.toScala().header().status());
            Logger.info(result.toScala().body().toString());
            return result;
        });
        return resultPromise;
    }
}

Тело будет возвращено как play.api.libs.iteratee.Enumerator. Теперь самое сложное — работать с этим. Сначала нужно понять концепцию Iteratee и какую роль в ней играет Enumerator. Совет: считайте Enumerator производителем данных, а Iteratee — их потребителем.

Теперь на этом Enumerator вы можете запустить Iteratee, который преобразует фрагменты данных в нужный вам тип.

Плохая новость заключается в том, что вам нужно реализовать трейт play.api.libs.iteratee.Iteratee. Как видите, он находится в подпакете api, что означает, что он является частью мира Scala в Play. Возможно, в этом случае будет намного проще использовать Scala для этой части вашей задачи. К сожалению, я не могу предоставить вам пример реализации, но я надеюсь, что это будет не так сложно. Я думаю, что этого действительно не хватает на Java-стороне Play.

person Anton    schedule 02.10.2014
comment
Спасибо за ответ, однако, хотя он кажется в правильном направлении, по какой-то причине я регистрирую это - play.api.libs.iteratee.Enumerator$$anon$18@2ae9a7b2 вместо тела ответа. - person Caballero; 02.10.2014