0
votes

I started learning Netty 4 Http Server, but already I have a problem. How can we get content from POST request in the simplest way?

I'm browsing Netty's documentation, but it's complex.

Thanks in advance!


EDIT: I'm using this code to receive data.

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;

import static io.netty.handler.codec.http.HttpHeaders.Names.*;
import static io.netty.handler.codec.http.HttpHeaders.Values;
import io.netty.handler.codec.http.HttpRequest;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import java.io.IOException;
import java.util.List;

public class HttpServerHandler extends ChannelInboundHandlerAdapter
{

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx)
    {
        ctx.flush();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws IOException
    {
        if (msg instanceof HttpRequest) {
            HttpRequest req = (HttpRequest) msg;

            if (HttpHeaders.is100ContinueExpected(req)) {
                ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
            }
            boolean keepAlive = HttpHeaders.isKeepAlive(req);

            /*
            HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
            List<InterfaceHttpData> list = decoder.getBodyHttpDatas();
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i));
            }
            */

            String message = "Lorem ipsum dolorem";
            byte[] byty = message.getBytes();

            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(byty));
            response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
            response.headers().set(CONTENT_TYPE, "text/plain; charset=utf-8");
            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());

            if (!keepAlive) {
                ctx.write(response).addListener(ChannelFutureListener.CLOSE);
            } else {
                response.headers().set(CONNECTION, Values.KEEP_ALIVE);
                ctx.write(response);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
    {
        cause.printStackTrace();
        ctx.close();
    }
}

As you can see there are three commented lines which return me an exception:

io.netty.handler.codec.http.multipart.HttpPostRequestDecoder$NotEnoughDataDecoderException at io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.getBodyHttpDatas(HttpPostRequestDecoder.java:339) at httpServer.HttpServerHandler.channelRead(HttpServerHandler.java:64) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:163) at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:147) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354) at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116) at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137) at java.lang.Thread.run(Thread.java:745)

The sending code looks like this:

var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "http://127.0.0.1:8030", true);
xmlhttp.send("json=value");
1
provide some code that you have been tested.Nikola Dimitrovski

1 Answers

0
votes

Looks like you are mixing things up a bit here. The decoders probably sit better in the pipeline initialiser that's called from the ServerBootstrap.

The example below is extracted from the Manning press book Netty in Action:

    public class HttpDecoderEncoderInitializer
        extends ChannelInitializer<Channel> {
        private final boolean client;
        public HttpDecoderEncoderInitializer(boolean client) {
            this.client = client;
        }
        @Override
        protected void initChannel(Channel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            if (client) {
                pipeline.addLast("decoder", new HttpResponseDecoder());
                pipeline.addLast("encoder", new HttpRequestEncoder());
            } else {
                pipeline.addLast("decoder", new HttpRequestDecoder());
                pipeline.addLast("encoder", new HttpResponseEncoder());
            }
        }
    }

The API docs / source code also has some easy to follow HTTP examples (in an example folder).

One you put the decoder in the pipeline you can operate directly on the req object in your handler as it will have been "decoded" from bytes into an HttpMessage object.