Netty实现HTTP客户端
这是用netty写的http客户端,没什么好说的,细节直接看代码
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======