Akka http从指令返回异步响应(java)

时间:2016-07-01 15:02:31

标签: java akka akka-http

我希望有一个基于演员的服务,可通过http访问 我是akka的新手,但经过研究,我得出结论,使用akka http对我来说是最好的方法。

我正在实现一个使用akka http的服务器,如下所示:

class MyServer extends AllDirectives {
    private final Http http;
    private final Materializer materializer;
    private final Flow<HttpRequest, HttpResponse, NotUsed> routes;

    private ServerBinding binding;

    MyServer(final ActorSystem system) {
        this.http = Http.get(system);
        this.materializer = ActorMaterializer.create(system);
        this.routes = this.createRoutes().flow(system, materializer);
    }

    CompletionStage<ServerBinding> start() {
        return this.http
                .bindAndHandle(this.routes, ConnectHttp.toHost("localhost", DEFAULT_PORT), this.materializer)
                .thenApplyAsync(serverBinding -> {
                    this.binding = serverBinding;
                    return serverBinding;
                });
    }

    CompletionStage<BoxedUnit> stop() {
        return this.binding.unbind();
    }

    private Route createRoutes() {
        // create routes 
    }
}

createRoutes方法中,我想使用指令创建分层路由树(或林),如:

private Route createRoutes() {
    return pathPrefix("typeOne", () ->
                path(PathMatchers.segment(), id ->
                    get(() -> handleTypeOneGetRequest(id))
                    .orElse(post(() -> handleTypeOnePostRequest(id, requestData)))
                )
            ).orElse(pathPrefix("typeTwo", () ->
                path(PathMatchers.segment(), id ->
                        get(() -> handleTypeTwoGetRequest(id))
                        .orElse(post(() -> handleTypeTwoPostRequest(id, requestData)))
                )
    ));
}

处理请求时(例如handleTypeOneGetRequest)我想将消息传递给相应的参与者(例如TypeOne)并返回异步响应,该响应将在响应时完成消息从演员返回。

我的问题是,在处理指令时,我无法弄清楚如何访问RequestContext

我的问题是:

  • 如何获取指令中的RequestContext
  • 我是以正确的方式来做这件事的吗?有更好的方法吗?

1 个答案:

答案 0 :(得分:2)

我不确定我的问题是否正确,但据我所知,您希望基本上让演员处理您的请求然后返回结果。我通常使用Scala,所以请不要介意我的Java8代码中可能的语法错误;)

我通常使用akka ask模式来检索actor发送的响应对象的未来,然后使用onSuccess指令从未来提取实际值。 由于参与者的响应默认为无类型,因此您需要检查它是否符合您的预期,然后您可以使用该值完成请求。 (你可能还需要施放对象,所以你的反应编组工作了。)

Timeout timeout = new Timeout(Duration.create(5, "seconds"));    

private Route createRoutes() {
    return pathPrefix("typeOne", () ->
                path(PathMatchers.segment(), id ->
                    get(() -> 
                            onSuccess(() -> Patterns.ask(actor, id, timeout),
                                      extraction -> if (extraction instanceof WhatEverYouExpect) complete(extraction)
                                     )
                        )
    ));
}

询问模式:http://doc.akka.io/docs/akka/snapshot/java/futures.html

onSuccess指令:http://doc.akka.io/docs/akka/snapshot/java/http/routing-dsl/directives/future-directives/onSuccess.html

修改

你应该看一下extract *指令: http://doc.akka.io/docs/akka/2.4.7/java/http/routing-dsl/directives/alphabetically.html

具体提取: http://doc.akka.io/docs/akka/2.4.7/java/http/routing-dsl/directives/basic-directives/extract.html#extract-java

final Route route = extract(
  ctx -> ctx.getRequest().getUri().toString().length() // extract anything you need and pack into your object
  len -> //use your object
);

我想这就是你需要的。

编辑(由OP)

以下是该问题的完整解决方案,包括HttpContext,异常响应Actor的使用以及如何使其在java中运行:

pathPrefix("typeOne", () ->
    path(PathMatchers.segment(), segment ->
        get(() ->
            extract(
                context -> context,
                context -> onSuccess(() -> 
                    FutureConverters.toJava(Patterns.ask(ACTOR_REF, MESSAGE, TIMEOUT)),
                    extraction -> complete(DO_SOMETHING_WITH(segment, context, extraction))
                ).orElse(...)
            )
        )
    )
)