Gevlet 源码分享之网络请求处理
网络服务相关代码主要在connector 下,统一抽象为一个 BackendServer 对象,后续其他的网络协议可以实现此接口进行扩展
import io.netty.channel.socket.SocketChannel;
/**
BackendServer 有两个方法
1.start 用于启动某个网络服务,可以指定端口
2.setSocketChannel 用于指定处理该协议请求的处理类
*/
public interface BackendServer {
void start(int port) throws Exception;
void setSocketChannel(SocketChannel channel);
}
目前 BackendServer 只有一个实现类 HttpBackendServer 用于处理 HTTP 协议的请求
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import java.net.InetSocketAddress;
public class HttpBackendServer implements BackendServer {
@Override
public void start(int port) throws InterruptedException {
ServerBootstrap serverBootstrap = new ServerBootstrap();
EventLoopGroup group = new NioEventLoopGroup();
try {
serverBootstrap.group(group);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.localAddress(new InetSocketAddress(port));
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {//有连接到达时会创建一个channel
protected void initChannel(SocketChannel channel) throws Exception {
setSocketChannel(channel);
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = serverBootstrap.bind().sync();
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
group.shutdownGracefully().sync();
}
}
@Override
public void setSocketChannel(SocketChannel channel) {
channel.pipeline().addLast(new HttpResponseEncoder());
channel.pipeline().addLast(new HttpRequestDecoder());
channel.pipeline().addLast(new HttpRequestHandlerAdapter());
}
}
HttpRequestHandlerAdapter 是具体的HTTP 请求处理类
import com.gevlet.coop.Utils.Strings;
import com.gevlet.coop.connector.protocol.ByteBufferReader;
import com.gevlet.coop.connector.protocol.NetMessagetProtocol;
import com.gevlet.coop.core.ServerRequestHolder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.EmptyByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import java.util.HashMap;
public class HttpRequestHandlerAdapter extends AbstractHandlerAdapter {
private NetMessagetProtocol protocol;
private ByteBufferReader bufferReader;
@Override
protected void doRequest(ChannelHandlerContext context, Object message) throws Exception {
//处理请求头
buildHttpRequest(message);
//处理请求参数
buildHttpContentAndProcess(context, message);
}
/**
* 处理请求头
*
* @param message
*/
private void buildHttpRequest(Object message) {
if (message instanceof HttpRequest) {
initialize();
HttpRequest request = (HttpRequest) message;
buildUrl(request.uri());
if (HttpUtil.isContentLengthSet(request)) {
bufferReader = new ByteBufferReader(
(int) HttpUtil.getContentLength(request));
}
}
}
/**
* 处理请求参数
*
* @param context
* @param message
*/
private void buildHttpContentAndProcess(ChannelHandlerContext context, Object message) {
if (message instanceof HttpContent) {
HttpContent httpContent = (HttpContent) message;
ByteBuf content = httpContent.content();
if (content instanceof EmptyByteBuf) {
//处理业务请求
ServerRequestHolder.newInstance().holdRequest(protocol);
destroy();
return;
} else {
bufferReader.reading(content);
content.release();
if (bufferReader.isEnd()) {
HashMap<String, String> contentData = getContentData(content);
protocol.setBody(contentData);
protocol.setHandlerContext(context);
//处理业务请求
ServerRequestHolder.newInstance().holdRequest(protocol);
//销毁请求参数
destroy();
}
}
}
}
private void destroy() {
protocol = null;
bufferReader = null;
}
private HashMap<String, String> getContentData(ByteBuf content) {
HashMap<String, String> dataMap = new HashMap<>();
String resultStr = new String(bufferReader.readFull());
if (!Strings.isEmpty(resultStr)) {
String[] splitedResult = resultStr.split("\n");
int roudNum = splitedResult.length / 4;
for (int i = 0; i < roudNum; i++) {
String key = splitedResult[i * 4 + 1].
replace("\r", "").
replace("Content-Disposition: form-data; name=\"", "");
String keyResult = key.substring(0, key.length() - 1);
String value = splitedResult[i * 4 + 3].replace("\r", "");
//设置值
dataMap.put(keyResult, value);
}
}
return dataMap;
}
private void buildUrl(String url) {
if (Strings.isEmpty(url)) {
protocol.setThrowable(new NullPointerException("URL 不能为空"));
}
if ("/".equals(url)) {
protocol.setApplication("/");
} else {
String[] splitedUrl = url.split("/");
protocol.setApplication(splitedUrl[1]);
protocol.setPathUrl(splitedUrl[2]);
protocol.setHandlerUrl(splitedUrl[3]);
protocol.setProtocolType("HTTP");
}
}
private void initialize() {
this.protocol = new NetMessagetProtocol();
this.bufferReader = null;
}
}