Netty实现HTTP服务器(含:请求处理控制器)
本文将使用Netty框架实现HTTP服务器,然后进行请求处理。
创建Http Server
public class HttpServer {
/**
* 服务开始
*/
public static void start() {
ServerBootstrap bootstrap = new ServerBootstrap();
EventLoopGroup boss = new NioEventLoopGroup();
EventLoopGroup work = new NioEventLoopGroup();
bootstrap.group(boss, work)
.handler(new LoggingHandler(LogLevel.DEBUG))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(new HttpServerCodec());// http 编解码
pipeline.addLast("httpAggregator", new HttpObjectAggregator(100 * 1024 * 1024)); // http 消息聚合器 512*1024为接收的最大contentlength
pipeline.addLast(new HttpServerExpectContinueHandler());
pipeline.addLast(new HttpServerHandler());
}
}).childOption(ChannelOption.SO_KEEPALIVE, true);
//获取配置文件的端口
String port = PropertiesUtil.readByKey("http.port");
try {
//绑定端口,同步等待成功
ChannelFuture future = bootstrap.bind(Integer.valueOf(port)).sync();
StaticLog.info("http server start up on port : " + port);
//关闭监听端口,同步等待
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 退出
boss.shutdownGracefully();
work.shutdownGracefully();
}
}
}
创建Http Server Handler
这里的示例支持POST请求的API,form-data格式参数和body格式(JSON对象字符串)参数;
支持一次响应(写入一次response)和请求多次响应(多次写入response流);
设计思路:
参数中必传属性:sign, 对应springboot框架的controller handler。这个字段对应HttpRequestHandler的方法名。
可选属性:responseType,如果需要多次响应需要传递,需要自己关闭连接(channel)。
请求处理方法名格式:
XXXXXX Stringsign
(JSONObject obj);
XXXXXX Stringsign
(HashMap<String, Object> map);
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws InterruptedException {
String url = request.uri();
if (url.endsWith("/api")){ //接口相关
apiHandler(ctx, request);
} else if (url.endsWith("/ping")) { //ping
responseOK(ctx, "OK");
} else {
responseError(ctx, "url error");
}
}
private void apiHandler(ChannelHandlerContext ctx, FullHttpRequest request){
// 获取通道
Channel channel = ctx.channel();
//请求内容
String body = request.content().toString(CharsetUtil.UTF_8);
//请求Type
String method = request.method().name();
//---------
//记录接口日志....省略
//---------
try {
//判断请求Type 这里仅仅支持POST请求
if (!"POST".equals(method.toUpperCase())) {
String msgData = "unsupported request type: " + method;
responseError(ctx, msgData);
return;
}
//调用方法
String methodSign = "";
Object content = null; //调用方法参数内容
Class clazz = null; //参数类型
String responseType; //响应类型
if (JSONUtil.isJsonObj(body)) {
JSONObject bodyJson = JSONUtil.parseObj(body);
methodSign = bodyJson.getStr("sign");
responseType = bodyJson.getStr("responseType");
content = bodyJson;
clazz = JSONObject.class;
} else {
//不是json 数据--另外解析
HashMap<String,Object> map = getRequestParameters(request);
methodSign = String.valueOf(map.get("sign"));
responseType = String.valueOf(map.get("responseType"));
content = map;
clazz = HashMap.class;
}
try {
if (responseType != null && responseType.equals("custom")) {
//自定义响应用于特殊情况,需要自己关闭channel,需要自己保存日志
Method methodFunc = HttpRequestHandler.class.getDeclaredMethod(methodSign, clazz, ChannelHandlerContext.class, SysOperLog.class);
methodFunc.setAccessible(true);
methodFunc.invoke(HttpRequestHandler.getInstance(), content, ctx, sysOperLog);
return;
} else {
Method methodFunc = HttpRequestHandler.class.getDeclaredMethod(methodSign, clazz);
methodFunc.setAccessible(true);
String invokeResult = (String) methodFunc.invoke(HttpRequestHandler.getInstance(),content);
responseOK(ctx, invokeResult);
}
} catch (NoSuchMethodException e) {
Static.info(String.format("sign 参数错误, %s 不属于可选值", methodSign))
}
} catch (Exception e){
String msg = "";
if (e instanceof InvocationTargetException) {
msg = ((InvocationTargetException)e).getTargetException().getMessage();
} else {
msg = e.getMessage();
}
responseError(ctx, Optional.ofNullable(msg).orElse("handler deal failed!"))
}
}
private HashMap<String, Object> getRequestParameters(FullHttpRequest request) throws IOException {
HashMap<String,Object> map = new HashMap<>();
HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(factory, request);
List<InterfaceHttpData> dataList = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : dataList) {
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
MixedFileUpload fileUpload = (MixedFileUpload) data;
map.put(fileUpload.getName(),fileUpload.getFile());
} else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
MixedAttribute attribute = (MixedAttribute) data;
map.put(data.getName(),attribute.getString(Charset.forName("utf-8")));
}
}
return map;
}
/**
* 返回处理结果
* @param apiResult 数据
* @return 返回数据
*/
private ApiResult response(ChannelHandlerContext ctx, ApiResult apiResult){
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, Unpooled.wrappedBuffer(apiResult.toJSONStr().getBytes()));
response.headers().set("Content-Type", "application/json; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
return apiResult;
}
private ApiResult responseOK(ChannelHandlerContext ctx, String data) {
return response(ctx, ApiResult.OK(data));
}
private ApiResult responseError(ChannelHandlerContext ctx, String data) {
return response(ctx, ApiResult.ERROR(data));
}
}
创建HttpRequestHandler
用于request请求的处理器
public class HttpRequestHandler {
private static class SingletonHolder {
private static HttpRequestHandler instance = new HttpRequestHandler();
}
public static HttpRequestHandler getInstance() {
return SingletonHolder.instance;
}
private HttpRequestHandler() {
}
//其他处理方法
private String test(JSONObject obj){ return "OK"};
private String test2(HashMap<String,Object> obj){ return "OK"};
}
以上就是Netty 创建HTTP服务器以及处理Http请求以及响应的主要代码实现,可供参考;