tio-boot异步响应
tio-boot 的响应本身就是异步的,但是如果你想要在发送 http 响应之后在做一些事情,可以参考本节的内容
tio-boot 异步地发送 HTTP 响应
- 获取 ChannelContext:
ChannelContext channelContext = request.getChannelContext();
从HttpRequest
获取ChannelContext
。ChannelContext
包含了当前连接的状态和配置信息。
- 准备发送的数据:
Map<String, Object> data = new HashMap<>();
data.put("code", 1);
创建一个包含响应数据的Map
,这里只放入了一个键值对。
- 封装为 HttpResponse:
HttpResponse httpResponse = TioControllerContext.getResponse();
httpResponse = Resps.json(httpResponse, data);
使用TioControllerContext.getResponse()
获取HttpResponse
对象,然后使用Resps.json
方法将data
封装为 JSON 格式的响应。
- 调用 Handler 进行解码:
TioConfig tioConfig = channelContext.getTioConfig();
AioHandler aioHandler = tioConfig.getAioHandler();
ByteBuffer writeBuffer = aioHandler.encode(httpResponse, tioConfig, channelContext);
获取AioHandler
,这是一个用于处理编码和解码的处理器。调用encode
方法将httpResponse
编码为可以通过网络发送的字节数据。
- 异步写入数据到客户端:
channelContext.asynchronousSocketChannel.write(writeBuffer, request, new CompletionHandler<Integer, HttpRequest>() {
使用channelContext.asynchronousSocketChannel.write
异步地将编码后的数据写入到客户端。同时传入request
作为attachment
,并定义了一个匿名的CompletionHandler
来处理写操作的结果。
- 处理写操作的结果:
- completed 方法:
public void completed(Integer result, HttpRequest attachment) {
log.info("result:{},attachment:{}", result, attachment);
try {
channelContext.asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
写操作成功完成时,会调用此方法。它记录了操作结果,并尝试关闭AsynchronousSocketChannel
。
- failed 方法:
public void failed(Throwable exc, HttpRequest attachment) {
try {
channelContext.asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
如果写操作失败,这个方法会被调用。它同样尝试关闭AsynchronousSocketChannel
。
这个方法展示了如何异步地发送 HTTP 响应,并通过CompletionHandler
处理操作的结果。通过这种方式,服务器可以在不阻塞当前线程的情况下处理多个连接和请求,从而提高性能。
AsynchronousSocketChannel 的 write 方法
AsynchronousSocketChannel
的write
方法是一个用于异步写操作的方法。它接收三个参数,这些参数的含义如下:
- ByteBuffer src:
这是一个ByteBuffer
对象,它包含了要写入通道的数据。当调用write
方法时,数据会从这个缓冲区写入到通道中。ByteBuffer 提供了一个接口,通过这个接口可以以高效的方式读写多个字节,常用于 NIO 的数据输入输出。 - A attachment: attachment 参数是传递到 CompletionHandler 中的。当你创建一个异步操作时,你可以提供一个 attachment 对象。这个对象可以是任何类型的数据,它会被传递给 CompletionHandler 的 completed 或者 failed 方法。
- CompletionHandler<Integer,? super A> handler:
这是一个CompletionHandler
接口的实现。当异步操作完成时,无论是成功还是失败,都会调用这个处理器的方法。处理器有两个方法:completed
和failed
。如果操作成功完成,会调用completed
方法,并且会将写入的字节数作为参数传递给它。如果操作失败,会调用failed
方法,并且会将导致失败的异常作为参数传递给它。这个处理器的泛型参数<Integer,? super A>
表示它接受一个Integer
类型的结果(这里是写入的字节数),以及一个A
类型或其父类型的附件对象。
示例
示例代码
package com.litongjava.tio.web.hello.controller;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.CompletionHandler;
import java.util.HashMap;
import java.util.Map;
import com.litongjava.tio.boot.http.TioControllerContext;
import com.litongjava.tio.core.ChannelContext;
import com.litongjava.tio.core.TioConfig;
import com.litongjava.tio.core.intf.AioHandler;
import com.litongjava.tio.http.common.HttpRequest;
import com.litongjava.tio.http.common.HttpResponse;
import com.litongjava.tio.http.server.annotation.RequestPath;
import com.litongjava.tio.http.server.util.Resps;
import lombok.extern.slf4j.Slf4j;
@RequestPath("/async")
@Slf4j
public class AsyncController {
public Map<String, Object> index(HttpRequest request) {
ChannelContext channelContext = request.getChannelContext();
TioConfig tioConfig = channelContext.getTioConfig();
AioHandler aioHandler = tioConfig.getAioHandler();
String token = channelContext.getToken();
Map<String, Object> data = new HashMap<>();
data.put("channelContext", channelContext.toString());
data.put("tioConfig", tioConfig.toString());
data.put("userId", channelContext.userid);
data.put("token", token);
data.put("asynchronousSocketChannel", channelContext.asynchronousSocketChannel.toString());
data.put("aioHandler", aioHandler.toString());
log.info("data:{}", data);
return data;
}
public String writeHttpResponse(HttpRequest request) {
ChannelContext channelContext = request.getChannelContext();
// 准备发送的数据
Map<String, Object> data = new HashMap<>();
data.put("code", 1);
// 封装为httpResponse
HttpResponse httpResponse = TioControllerContext.getResponse();
httpResponse = Resps.json(httpResponse, data);
// 调用Handler进行解码
TioConfig tioConfig = channelContext.getTioConfig();
AioHandler aioHandler = tioConfig.getAioHandler();
ByteBuffer writeBuffer = aioHandler.encode(httpResponse, tioConfig, channelContext);
// 异步写入数据到客户端
channelContext.asynchronousSocketChannel.write(writeBuffer);
return null;
}
public String writeHttpResponseWithCompletionHandler(HttpRequest request) {
ChannelContext channelContext = request.getChannelContext();
// 准备发送的数据
Map<String, Object> data = new HashMap<>();
data.put("code", 1);
// 封装为httpResponse
HttpResponse httpResponse = TioControllerContext.getResponse();
httpResponse = Resps.json(httpResponse, data);
// 调用Handler进行解码
TioConfig tioConfig = channelContext.getTioConfig();
AioHandler aioHandler = tioConfig.getAioHandler();
ByteBuffer writeBuffer = aioHandler.encode(httpResponse, tioConfig, channelContext);
// 异步写入数据到客户端
channelContext.asynchronousSocketChannel.write(writeBuffer, request, new CompletionHandler<Integer, HttpRequest>() {
@Override
public void completed(Integer result, HttpRequest attachment) {
// 进行其他操作
log.info("result:{},attachment:{}", result, attachment);
// 手动关闭连接
try {
channelContext.asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void failed(Throwable exc, HttpRequest attachment) {
try {
channelContext.asynchronousSocketChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
return null;
}
}
访问测试
{
"aioHandler": "com.litongjava.tio.boot.server.TioBootServerHandler@7a041eef",
"tioConfig": "ServerTioConfig [name=tio-boot]",
"channelContext": "server:0.0.0.0:80, client:0:0:0:0:0:0:0:1:4986",
"asynchronousSocketChannel": "sun.nio.ch.WindowsAsynchronousSocketChannelImpl[connected local=/0:0:0:0:0:0:0:1:80 remote=/0:0:0:0:0:0:0:1:4986]"
}
{"code":1}
{"code":1}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。