Netty实现HTTP客户端
这是用netty写的http客户端,没什么好说的,细节直接看代码
package http2; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; import io.netty.handler.codec.http.multipart.HttpDataFactory; import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-6-25 * Time: 下午2:44 * To change this template use File | Settings | File Templates. */ public class Client { public static HttpRequest getRequestMethod(Map<String, String> parameter, String url, String method) throws HttpPostRequestEncoder.ErrorDataEncoderException { URI uri; try { uri = new URI(url); } catch (URISyntaxException e) { e.printStackTrace(); return null; } String path = uri.getRawPath(); String host = uri.getHost(); HttpRequest request = null; if ("post".equalsIgnoreCase(method)) { request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.POST, path); HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); // This encoder will help to encode Request for a FORM as POST. HttpPostRequestEncoder bodyRequestEncoder = new HttpPostRequestEncoder(factory, request, false); // add Form attribute if (parameter != null) { Set<Map.Entry<String, String>> entrySet = parameter.entrySet(); for (Map.Entry<String, String> e : entrySet) { String key = e.getKey(); String value = e.getValue(); bodyRequestEncoder.addBodyAttribute(key, value); } try { request = bodyRequestEncoder.finalizeRequest(); } catch (HttpPostRequestEncoder.ErrorDataEncoderException e) { // if an encoding error occurs e.printStackTrace(); } } request.headers().set(HttpHeaders.Names.HOST, host); request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); request.headers().set(HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode( new DefaultCookie("my-cookie", "foo"), new DefaultCookie("another-cookie", "bar"))); } else if ("get".equalsIgnoreCase(method)) { //uri.toString()没有查询参数的uri QueryStringEncoder encoder = new QueryStringEncoder(uri.toString()); if (parameter != null) { Set<Map.Entry<String, String>> entrySet = parameter.entrySet(); for (Map.Entry<String, String> e : entrySet) { String key = e.getKey(); String value = e.getValue(); encoder.addParam(key, value); } } //encoder.toString()有查询参数的uri request = new DefaultFullHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, encoder.toString()); HttpHeaders headers = request.headers(); headers.set(HttpHeaders.Names.HOST, host); headers.set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE); headers.set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP.toString() + ',' + HttpHeaders.Values.DEFLATE.toString()); headers.set(HttpHeaders.Names.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.7"); headers.set(HttpHeaders.Names.ACCEPT_LANGUAGE, "fr"); headers.set(HttpHeaders.Names.USER_AGENT, "Netty Simple Http Client side"); headers.set(HttpHeaders.Names.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); headers.set(HttpHeaders.Names.COOKIE, ClientCookieEncoder.encode( new DefaultCookie("my-cookie", "foo"), new DefaultCookie("another-cookie", "bar")) ); } else { System.err.println("this method is not support!"); } return request; } public void run(String url, HttpRequest request) throws HttpPostRequestEncoder.ErrorDataEncoderException, InterruptedException { URI uri; try { uri = new URI(url); } catch (URISyntaxException e) { e.printStackTrace(); return; } String scheme = uri.getScheme() == null ? "http" : uri.getScheme(); String host = uri.getHost() == null ? "localhost" : uri.getHost(); int port = uri.getPort(); if (port == -1) { if ("http".equalsIgnoreCase(scheme)) { port = 80; } else if ("https".equalsIgnoreCase(scheme)) { port = 443; } } if (!"http".equalsIgnoreCase(scheme) && !"https".equalsIgnoreCase(scheme)) { System.err.println("Only HTTP(S) is supported."); } boolean ssl = "https".equalsIgnoreCase(scheme); // Configure the client. EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(NioSocketChannel.class) .handler(new HttpClientInitializer(ssl)); // Make the connection attempt. Channel ch = b.connect(host, port).sync().channel(); // send request ch.writeAndFlush(request).sync(); ch.closeFuture().sync(); } finally { group.shutdownGracefully(); } } public static void main(String args[]) throws HttpPostRequestEncoder.ErrorDataEncoderException, InterruptedException { String url = "http://www.cnivi.com.cn/curriculum/search.html"; Map<String, String> getData = new HashMap<String, String>(); getData.put("tags", "806:938356;"); getData.put("sort", "_p"); HttpRequest get = getRequestMethod(getData, url, "get"); new Client().run(url, get); } }
package http2; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpContentDecompressor; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; import io.netty.handler.ssl.SslHandler; import javax.net.ssl.SSLEngine; public class HttpClientInitializer extends ChannelInitializer<SocketChannel> { private final boolean ssl; public HttpClientInitializer(boolean ssl) { this.ssl = ssl; } @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline p = ch.pipeline(); p.addLast("log", new LoggingHandler(LogLevel.INFO)); if (ssl) { SSLEngine engine = SslContextFactory.getClientContext().createSSLEngine(); engine.setUseClientMode(true); p.addLast("ssl", new SslHandler(engine)); } p.addLast("request-encoder", new HttpRequestEncoder()); p.addLast("response-decoder", new HttpResponseDecoder()); // Remove the following line if you don't want automatic content decompression. p.addLast("inflater", new HttpContentDecompressor()); //HttpObjectAggregator会把多个消息转换为 一个单一的FullHttpRequest或是FullHttpResponse //p.addLast("aggregator", new HttpObjectAggregator(1048576)); p.addLast("handler", new HttpClientHandler()); } }
package http2; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-6-25 * Time: 下午2:49 * To change this template use File | Settings | File Templates. */ public class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> { public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); if (msg instanceof HttpResponse) { HttpResponse response = (HttpResponse) msg; System.out.println("STATUS: " + response.getStatus()); System.out.println("VERSION: " + response.getProtocolVersion()); System.out.println(); if (!response.headers().isEmpty()) { for (String name : response.headers().names()) { for (String value : response.headers().getAll(name)) { System.out.println("HEADER: " + name + " = " + value); } } System.out.println(); } if (HttpHeaders.isTransferEncodingChunked(response)) { System.out.println("CHUNKED CONTENT {"); } else { System.out.println("CONTENT {"); } } if (msg instanceof HttpContent) { HttpContent content = (HttpContent) msg; System.out.print(content.content().toString(CharsetUtil.UTF_8)); System.out.flush(); if (content instanceof LastHttpContent) { System.out.println("} END OF CONTENT"); } } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { messageReceived(ctx, msg); } }
这是完整的netty实现的http客户端的代码。
//HttpObjectAggregator会把多个消息转换为 一个单一的FullHttpRequest或是FullHttpResponse
//p.addLast("aggregator", new HttpObjectAggregator(1048576));
这句代码对handler的处理方式有很大不同。如果注释掉这行代码,则对应的handler应该这样处理
package http3; import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.*; import io.netty.util.CharsetUtil; import java.nio.charset.Charset; /** * Created with IntelliJ IDEA. * User: ASUS * Date: 14-6-25 * Time: 下午2:49 * To change this template use File | Settings | File Templates. */ public class HttpClientHandler extends SimpleChannelInboundHandler<HttpObject> { public void messageReceived(ChannelHandlerContext ctx, HttpObject msg) throws Exception { System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); DefaultFullHttpResponse fullHttpResponse = (DefaultFullHttpResponse) msg; System.out.println("STATUS: " + fullHttpResponse.getStatus()); System.out.println("VERSION: " + fullHttpResponse.getProtocolVersion()); System.out.println(); if (!fullHttpResponse.headers().isEmpty()) { for (String name : fullHttpResponse.headers().names()) { for (String value : fullHttpResponse.headers().getAll(name)) { System.out.println("HEADER: " + name + " = " + value); } } System.out.println(); } if (HttpHeaders.isTransferEncodingChunked(fullHttpResponse)) { System.out.println("CHUNKED CONTENT {"); } else { System.out.println("CONTENT {"); ByteBuf content = fullHttpResponse.content(); System.out.println(content.toString(CharsetUtil.UTF_8)); System.out.println("} END OF CONTENT"); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } @Override protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { messageReceived(ctx, msg); } }
======END======