Netty Base Http Client example Code
NettyHttpClient
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | public class NettyClient { ChannelFuture cf; EventLoopGroup group; public void connect(String host, int port) { group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY, true) .handler(new NettyHttpChannelInit(group)); cf = b.connect(host, port).sync(); // cf.channel().closeFuture().sync(); } catch (Exception e) { e.printStackTrace(); } } //post Request Encoder : attribute를 지정하고 싶다면, PostRquestEncoder를 통해 요청해야한다. public void createRequest(String host, int port, String url) throws Exception { HttpRequest request = null; HttpPostRequestEncoder postRequestEncoder = null; request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/create" // ,Unpooled.copiedBuffer(url.getBytes(CharsetUtil.UTF_8)) ); request.headers().set(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_X_WWW_FORM_URLENCODED); request.headers().set(HttpHeaderNames.HOST, host+":"+port); request.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); // request.headers().set(HttpHeaderNames.CONTENT_LENGTH, url.length()); postRequestEncoder = new HttpPostRequestEncoder(request, false); postRequestEncoder.addBodyAttribute("url", url); request=postRequestEncoder.finalizeRequest(); postRequestEncoder.close(); // cf.channel().writeAndFlush(request).addListener(ChannelFutureListener.CLOSE); cf.channel().writeAndFlush(request); // System.out.println(request.toString()); } public void close() { cf.channel().close(); group.shutdownGracefully(); } } |
-> 가장 중요한 부분은 Request Format이다. DefaultFullHttpRequest객체를 통해 http의 header, body를 직접 정의할 수 있다.
체크해야할 부분이 있다면, PostRequestEncoder. Post방식의 경우 요청 파라미터가 Url에 명시되지 않기 때문에, PostRequestEncoder를 통해 지정가능하다.
Channelinitializer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | public class NettyHttpChannelInit extends ChannelInitializer<SocketChannel>{ private boolean ssl = false; private EventLoopGroup group; public NettyHttpChannelInit(EventLoopGroup group) { this.group = group; } @Override protected void initChannel(SocketChannel sc) throws Exception { // TODO Auto-generated method stub ChannelPipeline p = sc.pipeline(); if(ssl) { SslContext sslCtx = null; try { sslCtx = SslContextBuilder.forClient() .trustManager(InsecureTrustManagerFactory.INSTANCE).build(); p.addLast(sslCtx.newHandler(sc.alloc())); } catch (SSLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } /** * * Message Decoder, FastLz... */ // p.addLast(new MessageDecoder()); //chunked 된 응답을 집계하는 코덱 p.addLast("chunked",new HttpObjectAggregator(1048576)); p.addLast("codec",new HttpClientCodec()); p.addLast(new NettyHttpHandler(group, sc)); } } | cs |
-> 채널을 초기화하는 객체에서는 서버에서 데이터를 받기 위해 여러 핸들러를 정의했다.
샘플 코드에서는 4개의 핸들러를 추가었다.
1) sslCtx.newHandler : SSL,TLS 성립된 서버와의 통신을 위해 추가된 코덱 (https에 해당한다.)
2)HttpObjectAggregator : chunked된 응답을 집계하는 코덱이다.
* Chunked
- Chunk Response, "덩어리 응답"은 전체 페이지를 가공하지 않는다.
- 즉, 서버측에서 html을 전부 생성한 후에 클라이언트에게 보내는 것이 아니라 html을 덩어리(chunk) 단위로 쪼개서 보낼 수 있다.
- 브라우저(클라이언트)에게 전체 컨텐츠 크기가 얼마나 큰지 알려주지 않아도된다는 특징이 있다.
- 따라서, 동적인 크기의 컨텐츠 및 스트리밍에 적합하고 Chunked transfer encoding을 사용해야하며 netty의 경우 httpObjectAggregator 코덱에 해당된다.
3) httpClientCodec
송신시에는 HttpClientCodec을 사용해야 하며. HttpResponseEncoder로 대신 사용할 수 있다.
pipeline.addLast("encoder", new HttpClientCodec());
pipeline.addLast("encoder", new HttpResponseEncoder());
수신시에는 HttpServerCodec를 사용해야 하며. 아래와 같이 HttpRequestDecoder대신 사용할 수 있다.
pipeline.addLast("decoder", new HttpServerCodec());
pipeline.addLast("decoder", new HttpRequestDecoder());
4) NettyHttpHandler : 사용자 정의 핸들러, SimpleChannelInboundHandler를 상속받은 사용자 정의 객체 입니다. 실제 메시지를 확인하기 위해 만들었다.
NettyClientHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | public class NettyHttpHandler extends SimpleChannelInboundHandler<HttpObject> { private EventLoopGroup group; private SocketChannel sc; private int count=0; public NettyHttpHandler(EventLoopGroup group, SocketChannel sc) { this.group = group; this.sc =sc; } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // TODO Auto-generated method stub super.channelActive(ctx); // System.out.println("connect:"+ctx.channel().isActive()); } @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { // TODO Auto-generated method stub // System.err.println(msg); if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; System.err.println("STATUS: " + response.status()); System.err.println("VERSION: " + response.protocolVersion()); if (!response.headers().isEmpty()) { for (CharSequence name : response.headers().names()) { for (CharSequence value : response.headers().getAll(name)) { System.err.println("HEADER: " + name + " = " + value); } } System.err.println(); } if (HttpUtil.isTransferEncodingChunked(response)) { System.err.println("CHUNKED CONTENT {"); } else { System.err.println("CONTENT {"); } } if (msg instanceof HttpContent) { count++; HttpContent content = (HttpContent) msg; System.err.println(count+". create url = "+content.content().toString(CharsetUtil.UTF_8)); System.err.flush(); if (content instanceof LastHttpContent) { System.err.println("} END OF CONTENT"); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); sc.close(); group.shutdownGracefully(); } | cs |
'Framework > Netty' 카테고리의 다른 글
Nety JVM Option (0) | 2018.12.02 |
---|---|
#NettyFramework - Echo Server, Client 구현 (0) | 2018.06.19 |
#Nettty Framework - Codec 종류 및 사용 (0) | 2018.05.21 |
#Nettty Framework - ByteBuffer, ByteBuf (0) | 2018.05.09 |
#Nettty Framework - ChannelFutureListener (0) | 2018.05.09 |