## 一、Http
建立在TCP傳輸協議之上的應用層協議,目前主流針對于WEB開發,Http協議應用非常廣泛
,因此掌握HTTP協議的開發之重要。Netty如何基于Http協議進行開發,那么使用Netty的Http
協議也是異步非阻塞的。
### Http協議的特點:
簡單:客戶端請求服務器時只需要指定URL和攜帶的參數
靈活:Http協議允許傳輸任意類型的數據對象,傳輸內容有Http消息頭中的Content-Type加以標記
### Http協議的組成
請求行
請求頭
請求正文
### Http協議
響應狀態種類
1xx :提示消息。表示請求已經接受繼續處理
2xx :成功 表示請求已經接受成功
3xx :重定向 要完成的請求必須進行進一步的操作
4xx :客戶端錯誤。可能是請求語法錯誤或者請求無法實現
5xx: 服務器錯誤。服務器未能處理請求(可能內部出現異常)
### 常見相應狀態碼
200 ok 成功
400 bad Request 錯誤請求語法,不能被服務理解
401 Unauthorized 請求未經授權
403 Forbidden 服務器收到請求,但是請求被服務器拒絕
404 Not Found 請求資源不存在
405 Method Not Allowed 請求方式不被允許,如只支持get請求,但客戶端使用post
請求
500 Inernal Server Error: 服務器發送不可預期的錯誤
503 Servr Unavailable:服務器當前不能處理客戶端的請求,一段時間后可能才能恢復正常
## 二、Netty與Http
### HttpHelloWorldServer
public final class HttpHelloWorldServer {
static final boolean SSL = System.getProperty("ssl") != null;
static final int PORT = Integer.parseInt(System.getProperty("port", SSL? "8443" : "8080"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
} else {
sslCtx = null;
}
// Configure the server.
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpHelloWorldServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
System.err.println("Open your web browser and navigate to " +
(SSL? "https" : "http") + "://127.0.0.1:" + PORT + '/');
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
### HttpHelloWorldServerInitializer
public class HttpHelloWorldServerInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
public HttpHelloWorldServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
}
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new HttpServerCodec());
p.addLast(new HttpHelloWorldServerHandler());
}
}
### HttpHelloWorldServerHandler
public class HttpHelloWorldServerHandler extends ChannelHandlerAdapter {
private static final byte[] CONTENT = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd' };
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
HttpRequest req = (HttpRequest) msg;
if (HttpHeaderUtil.is100ContinueExpected(req)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}
boolean keepAlive = HttpHeaderUtil.isKeepAlive(req);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(CONTENT));
response.headers().set(CONTENT_TYPE, "text/plain");
response.headers().setInt(CONTENT_LENGTH, response.content().readableBytes());
if (!keepAlive) {
ctx.write(response).addListener(ChannelFutureListener.CLOSE);
} else {
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
ctx.write(response);
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}