HttpPostRequestEncoder使用示例

文章目录

HttpServer

java 复制代码
public class HttpServer {

    public static void main(String[] args) {

        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<NioSocketChannel>() {

                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new HttpRequestDecoder());
                            ch.pipeline().addLast(new HttpResponseEncoder());
                            ch.pipeline().addLast(new HttpServerHandler());
                        }
                    });
            ChannelFuture bindFuture = serverBootstrap.bind(8080);
            Channel channel = bindFuture.sync().channel();
            System.out.println("---启动http服务成功---");
            channel.closeFuture().sync();
        } catch (Exception e) {
            System.out.println("---启动http服务失败---");
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        System.out.println("---http服务已关闭---");

    }
}

HttpServerHandler

java 复制代码
public class HttpServerHandler extends SimpleChannelInboundHandler<HttpObject> {

    HttpPostRequestDecoder decoder;
    HttpDataFactory factory;
    HttpRequest request;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject httpObject) throws Exception {
        System.out.println("[============> channelRead0]: " + httpObject);
        if (httpObject instanceof HttpRequest) {
            if (decoder != null) {
                decoder.destroy();
            }
            request = (HttpRequest) httpObject;
            factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
            decoder = new HttpPostRequestDecoder(factory, request);
        } else if (httpObject instanceof HttpContent) {
            decoder.offer(((HttpContent) httpObject));
            if (httpObject instanceof LastHttpContent) {
                for (InterfaceHttpData bodyHttpData : decoder.getBodyHttpDatas()) {
                    if (bodyHttpData.refCnt() > 0) {
                        handleHttpData(((HttpData) bodyHttpData));
                    }
                }
                decoder.destroy();
                decoder = null;
                sendResponse(ctx, request);
            } else {
                InterfaceHttpData next = null;
                while ((next = decoder.next()) != null) {
                    try {
                        handleHttpData(((HttpData) next));
                    } finally {
                        next.release();
                        decoder.removeHttpDataFromClean(next);
                    }
                }
            }
        } else {
            System.out.println("never reach here");
            ctx.fireChannelRead(httpObject);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("异常了...");
        cause.printStackTrace();
        ctx.close();
    }

    private void sendResponse(ChannelHandlerContext ctx, HttpRequest request) {
        DefaultFullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK,
                Unpooled.wrappedBuffer("请求处理完成".getBytes(CharsetUtil.UTF_8))
        );
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
        ChannelFuture channelFuture = ctx.writeAndFlush(response);
        // 客户端让我关, 我才关
        if (request.headers().contains(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE, true)) {
            System.out.println("添加关闭");
            channelFuture.addListener(future -> {
                ctx.channel().close();
            });
        }
    }

    private void handleHttpData(HttpData httpData) {
        if (httpData instanceof Attribute) {
            Attribute attribute = (Attribute) httpData;
            System.out.println("received attribute: " + attribute);
        } else if (httpData instanceof FileUpload) {
            FileUpload fileUpload = (FileUpload) httpData;
            System.out.println("received fileUpload: " + fileUpload);
            String filename = fileUpload.getFilename();
            String userDir = System.getProperty("user.dir");
            File file = new File(userDir + File.separator + "file" + File.separator + filename);
            if (file.exists() && file.isFile()) {
                file.delete();
            }
            try {
                fileUpload.renameTo(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

HttpClient

java 复制代码
public class HttpClient {

    public static void main(String[] args) {

        EventLoopGroup group = new NioEventLoopGroup(1);
        try {
            Bootstrap bootstrap = new Bootstrap()
                    .group(group)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<NioSocketChannel>() {
                        @Override
                        protected void initChannel(NioSocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new HttpResponseDecoder());
                            ch.pipeline().addLast(new HttpRequestEncoder());
                            ch.pipeline().addLast(new ChunkedWriteHandler());
                            ch.pipeline().addLast(new HttpClientHandler());
                        }
                    });
            ChannelFuture connectFuture = bootstrap.connect("127.0.0.1", 8080);
            Channel channel = connectFuture.sync().channel();
            System.out.println("---客户端连接http服务成功---");
            // 发送单个请求
            // sendSingleRequest(channel);
            // 发送多次请求
            // sendManyRequests(channel);
            // 发送文件上传请求
            sendPostData(channel);
            channel.closeFuture().sync();
        } catch (Exception e) {
            System.out.println("---客户端发生错误---");
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }

    }

    private static void sendPostData(Channel channel) throws HttpPostRequestEncoder.ErrorDataEncoderException {
        DefaultHttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/testEncoder");
        HttpPostRequestEncoder encoder = new HttpPostRequestEncoder(request, true);
        encoder.addBodyAttribute("name", "zzhua");
        encoder.addBodyAttribute("age", "18");
        encoder.addBodyFileUpload("mfile", new File("D:\\Projects\\practice\\demo-netty\\logs\\app.log"), null, false);
        HttpRequest httpRequest = encoder.finalizeRequest();
        channel.writeAndFlush(httpRequest);
        if (encoder.isChunked()) {
            channel.writeAndFlush(encoder);
        }
    }

    private static void sendManyRequests(Channel channel) {
        System.out.println("发第1个请求");
        sendSimplePost(channel);
        // try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {}
        System.out.println("发第2个请求");
        sendSimplePost(channel, true);
    }

    private static void sendSingleRequest(Channel channel, boolean... needClose) {
        System.out.println("发1个请求");
        sendSimplePost(channel, needClose);
    }

    private static ChannelFuture sendSimplePost(Channel channel, boolean... needClose) {
        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/test");
        if (needClose != null && needClose.length > 0 && needClose[0]) {
            request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
        }
        return channel.writeAndFlush(request);
    }
}

HttpClientHandler

java 复制代码
public class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
        System.out.println("[客户端received]: " + msg);
        if (msg instanceof HttpResponse) {
            HttpResponse response = (HttpResponse) msg;
            System.out.println("响应状态码: " + response.status());
            System.out.println("响应头: " + response.headers());
        } else if (msg instanceof HttpContent) {
            HttpContent httpContent = (HttpContent) msg;
            System.out.println("响应内容: " + httpContent.content().toString(CharsetUtil.UTF_8));
            if (httpContent instanceof LastHttpContent) {
                System.out.println("响应结束");
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("客户端异常");
        cause.printStackTrace();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客户端inactive");
    }
}

SimpleHttpClient

java 复制代码
public class SimpleHttpClient {
    private final EventLoopGroup workerGroup;
    private final Bootstrap bootstrap;

    public SimpleHttpClient() {
        workerGroup = new NioEventLoopGroup();
        bootstrap = new Bootstrap();
        bootstrap.group(workerGroup)
                .channel(NioSocketChannel.class)
                .option(ChannelOption.SO_KEEPALIVE, true)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline().addLast(new HttpClientCodec());
                        ch.pipeline().addLast(new HttpObjectAggregator(65536));
                    }
                });
    }

    /**
     * 发送HTTP请求
     * @param url 请求URL
     * @param method 请求方法
     * @param body 请求体内容
     * @param timeout 超时时间(秒)
     * @return 响应内容
     */
    public CompletableFuture<String> sendRequest(String url, HttpMethod method, 
                                                String body, int timeout) {
        CompletableFuture<String> future = new CompletableFuture<>();
        
        try {
            URI uri = new URI(url);
            String host = uri.getHost();
            int port = uri.getPort() != -1 ? uri.getPort() : 
                      (uri.getScheme().equals("https") ? 443 : 80);
            String path = uri.getRawPath() + (uri.getRawQuery() != null ? "?" + uri.getRawQuery() : "");

            // 创建HTTP请求
            FullHttpRequest request;
            if (body != null && !body.isEmpty()) {
                request = new DefaultFullHttpRequest(
                        HttpVersion.HTTP_1_1, 
                        method, 
                        path,
                        Unpooled.copiedBuffer(body, CharsetUtil.UTF_8)
                );
                request.headers().set(HttpHeaderNames.CONTENT_LENGTH, body.length());
            } else {
                request = new DefaultFullHttpRequest(
                        HttpVersion.HTTP_1_1, 
                        method, 
                        path
                );
            }

            // 设置请求头
            request.headers()
                    .set(HttpHeaderNames.HOST, host)
                    .set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE)
                    .set(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP)
                    .set(HttpHeaderNames.USER_AGENT, "SimpleNettyClient/1.0");

            if (body != null && !body.isEmpty()) {
                request.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
            }

            // 连接服务器
            ChannelFuture channelFuture = bootstrap.connect(host, port);
            channelFuture.addListener((ChannelFutureListener) f -> {
                if (f.isSuccess()) {
                    Channel channel = f.channel();
                    
                    // 添加响应处理器
                    channel.pipeline().addLast(new SimpleChannelInboundHandler<FullHttpResponse>() {
                        @Override
                        protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) {
                            try {
                                String content = response.content().toString(CharsetUtil.UTF_8);
                                future.complete("Status: " + response.status() + 
                                               "\nHeaders: " + response.headers() + 
                                               "\nBody: " + content);
                            } finally {
                                ctx.close();
                            }
                        }

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

                    // 发送请求
                    channel.writeAndFlush(request);
                } else {
                    future.completeExceptionally(f.cause());
                }
            });

        } catch (URISyntaxException e) {
            future.completeExceptionally(e);
        }

        // 设置超时
        workerGroup.schedule(() -> {
            if (!future.isDone()) {
                future.completeExceptionally(new RuntimeException("Request timeout"));
            }
        }, timeout, TimeUnit.SECONDS);

        return future;
    }

    /**
     * 发送GET请求(简化方法)
     */
    public CompletableFuture<String> get(String url) {
        return sendRequest(url, HttpMethod.GET, null, 10);
    }

    /**
     * 发送POST请求(简化方法)
     */
    public CompletableFuture<String> post(String url, String body) {
        return sendRequest(url, HttpMethod.POST, body, 10);
    }

    /**
     * 关闭客户端
     */
    public void shutdown() {
        workerGroup.shutdownGracefully();
    }

    public static void main(String[] args) throws Exception {
        SimpleHttpClient client = new SimpleHttpClient();

        try {
            // 示例1:发送GET请求
            System.out.println("=== Sending GET request ===");
            String getResponse = client.get("http://127.0.0.1:8080/abc").get(15, TimeUnit.SECONDS);
            System.out.println(getResponse);

            Thread.sleep(1000); // 等待一下

            // 示例2:发送POST请求
            System.out.println("\n=== Sending POST request ===");
            String postResponse = client.post("http://127.0.0.1:8080/abc",
                    "Hello from Netty!").get(15, TimeUnit.SECONDS);
            System.out.println(postResponse);

        } finally {
            client.shutdown();
        }
    }
}
相关推荐
lsswear5 小时前
swoole http 客户端
http·swoole
Arwen30316 小时前
IP地址证书的常见问题有哪些?有没有特殊渠道可以申请免费IP证书?
服务器·网络·网络协议·tcp/ip·http·https
蜂蜜黄油呀土豆1 天前
深入理解计算机网络中的应用层协议
网络协议·计算机网络·http
txinyu的博客1 天前
HTTP
网络·网络协议·http
bugcome_com1 天前
HTTP 状态码详解
网络·网络协议·http
Jack_abu1 天前
记录一次由yum update引起的http服务ERR_CONTENT_LENGTH_MISMATCH问题
http·tcpoom·yum update
于归pro1 天前
浅谈HTTP状态响应码
网络·网络协议·http
掘根1 天前
【JSONRpc项目】项目前置准备
服务器·网络·网络协议·http
派大鑫wink1 天前
【Day31】Web 开发入门:HTTP 协议详解(请求 / 响应、状态码、请求头)
前端·网络协议·http