利用netty4来实现http的服务器,代码如下:
public class ApiServer {
public static void main(String[] args) {
int port = 8089;
if (args != null && args.length > 0) {
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
}
}
try {
new ApiServer().bind(port);
System.out.println(String.format("start %s", port));
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
public void bind(int port) throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap boot = new ServerBootstrap();
boot.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel ch) throws Exception {
// server端是接收 ,所以这里是httprequest解码
ch.pipeline().addLast(new HttpRequestDecoder());
// 消息合并+最大2M,防止半包问题
ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(2 * 1024 * 1024));
//server端会返回respose 所以这里是进行编码
ch.pipeline().addLast(new HttpResponseEncoder());
//处理器
ch.pipeline().addLast(new HttpMessageHandler());
}
});
//绑定端口,同步等待成功
ChannelFuture f = boot.bind(port).sync();
System.out.println("yes bind"+port);
//等待服务端监听端口关闭;
f.channel().closeFuture().sync();
}
catch (Exception e) {
System.out.println(e.getMessage());
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
由于这里是实现server端的,所以对于接收的请求需要进行解码,另外在进行接收消息的时候为了避免半包的问题需要使用了读取消息的长度。最后这里会进行输出的响应,因此这里是使用了ReponseEncode。
在netty 4中,实现消息的处理是继承ChannelInboundHandlerAdapter 类,代码如下:
public class HttpMessageHandler extends ChannelInboundHandlerAdapter {
private static Log LOG=LogFactory.getLog(HttpMessageHandler.class);
//进行消息的接收
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//在这里进行读取内容
if(msg instanceof HttpRequest){
HttpRequest request=(HttpRequest)msg;
String url =request.uri();
//判断方法
Map<String, String> paramMap=new HashMap<String,String>();
if(request.method().name().equals(HttpMethod.GET.name())){
//get 请求
//获取参数
QueryStringDecoder parmDecoder= new QueryStringDecoder(url);
Map<String,List<String>> params=parmDecoder.parameters();
if(!params.isEmpty()){
params.forEach((k,v)->{
v.forEach(item->{
paramMap.put(k, item);
System.out.println(String.format("get %s:%s", k,item));
});
});
}
String res = "I am OK";
write(ctx, res, null);
//获取get的参数
}else if(request.method().name().equals(HttpMethod.POST.name())){
//post 请求
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request);
decoder.offer((HttpContent)request);
List<InterfaceHttpData> parmList = decoder.getBodyHttpDatas();
for (InterfaceHttpData parm : parmList) {
Attribute data = (Attribute) parm;
paramMap.put(data.getName(), data.getValue());
System.out.println(String.format("post %s_%s", data.getName(),data.getValue()));
}
String res = "I am OK";
write(ctx, res, null);
}
}else{
//进行返回404
String res = "404";
write(ctx, res, null);
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
//写入,发送回客户端
private void write(ChannelHandlerContext ctx,String res,String contentType) {
byte[] bytes=null;
try {
bytes=res.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
HttpResponseStatus.OK, Unpooled.wrappedBuffer(bytes));
if(contentType!=null){
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain");
}else{
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain");
}
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
response.content().readableBytes());
ctx.write(response);
ctx.flush();
}
}
在这里通过去判断request的方法类型来去获取参数,最后是通过FullHttpResponse来进行响应头的输出。