我尝试了解如何使用Undertow构建一个真正的异步http服务器。如果我有另一个正在处理请求的线程,如何异步发送响应? 我写了这样的代码:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(exchange -> {
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).thenAccept(string -> {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Hello World");
exchange.endExchange();
}).exceptionally(throwable -> {
System.out.println(throwable.toString());
return null;
});
}).build();
server.start();
但此服务器响应200没有数据且在日志中
java.lang.IllegalStateException:UT000127:已发送响应
当我像这样使用io.undertow.server.HttpServerExchange#dispatch(java.lang.Runnable)方法时:
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(exchange -> {
exchange.dispatch(() -> {
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).thenAccept(string -> {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE,"text/plain");
exchange.getResponseSender().send("Hello World");
exchange.endExchange();
}).exceptionally(throwable -> {
System.out.println(throwable.toString());
return null;
});
});
}).build();
server.start();
当然是回应" Hello World"正如所料,但服务器为每个请求创建新线程!
答案 0 :(得分:0)
承诺不支持这种方式,
我创建了一个新项目来解决它:
https://github.com/hank-whu/undertow-async
package io.undertow.async.pingpong;
import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import io.undertow.async.handler.AsyncHttpHandler;
import io.undertow.async.io.PooledByteBufferInputStream;
import io.undertow.async.io.PooledByteBufferOutputStream;
import io.undertow.connector.ByteBufferPool;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.StatusCodes;
public class PingPongAsyncHttpHandler extends AsyncHttpHandler {
@Override
protected void handleAsyncRequest(HttpServerExchange exchange, PooledByteBufferInputStream content)
throws Exception {
CompletableFuture//
.completedFuture(content)// init
.thenApplyAsync(this::readBytesAndClose)// read
.thenApplyAsync(bytes -> {// write
ByteBufferPool byteBufferPool = exchange.getConnection().getByteBufferPool();
PooledByteBufferOutputStream output = new PooledByteBufferOutputStream(byteBufferPool);
write(output, bytes);
return output;
})//
.thenAcceptAsync(output -> send(exchange, StatusCodes.OK, output));
}
private byte[] readBytesAndClose(PooledByteBufferInputStream content) {
try {
byte[] bytes = new byte[content.available()];
content.read(bytes);
return bytes;
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {// must close it
content.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void write(PooledByteBufferOutputStream output, byte[] bytes) {
try {
output.write("asycn response: ");
output.write(bytes);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}