Netty-Http文件上传下载

一、HTTP协议

HTTP(超文本传输协议)是建立在TCP传输协议之上的应用层协议,它目前主流是针对于WEB开发,HTTP协议应用非常广泛,因此掌握HTTP协议的开发非常之重要。我们主要讲解Netty如何基于HTTP协议进行开发,那么使用Netty的Http协议也是异步非阻塞的。

二、HTTP协议特点

简单:客户端请求服务器时只需要指定URL和携带必要的参数即可
灵活:Http协议允许传输任意类型的数据对象,传输内容由HTTP消息头中的Content-Type加以标记。
无状态:Http协议是无状态的,无状态指的是协议对事务处理没有记忆能力。这意味着如果后续处理需要之前的信息,则它必须重新获取。也从侧面体现Http的设计是为了使网络传输更加的轻量级、敏捷、负载较轻。

HTTP协议组成部分:请求行、请求头、请求正文(实体内容)

三、HTTP协议请求方式

GET:获取Request-URI所标识的资源

POST:在Request-URI所标识的资源附加新的提交数据

HEAD:请求获取由Request-URI所标识的资源的响应消息头

PUT:请求服务器存储一个资源,并用Request-URI作为标识

DELETE:请求服务器删除Request-URI所标识的资源
TRACE:请求服务器回送收到的请求信息,主要是测试和诊断使用(@trace)

CONNECT:保留将来使用
OPTIONS:请求查询服务器的性能忙活着查询相关资源的选项和需求。

四、HTTP协议的响应消息、状态种类、状态码

响应消息也是由三部分组成的:状态行、消息头、响应正文

响应状态种类

1xx:提示信息。表示请求已经接收继续处理。

2xx:成功。表示请求已经接收成功。
3xx:重定向。要完成的请求必须进行更进一步的操作。

4xx:客户端错误。可能是请求语法错误或者请求无法实现
5xx:服务器端错误。服务器未能处理请求(可能内部出现异常)。

常见相应状态码

200 OK:成功。
400 Bad Reuqest:错误的请求语法,不能被服务器理解。

401 Unauthorized:请求未经授权。
403 Forbidden:服务器收到请求,但请求被服务器拒绝。

404 Not Found:请求资源不存在
405 Method Not Allowed:请求方式不被允许,如只支持get请求,但客户端使用了post请求)
500 Inernal Server Error:服务器发送不可预期的错误。
503 Server Unavailable:服务器当前不能处理客户端请求,一段时间后可能恢复正常

五、Netty HTTP文件服务端开发

Netty的Http协议栈无论从性能上还是可靠性上都表现优异,非常适合WEB容器的场景下引用,相比于传统的Tomcat、Jetty等Web容器,它更加的轻量和小巧,灵活性和制定性也更好。

1、Netty实现简单的HTTP服务器 

我们来看一个简单的Netty实现HTTP服务器开发示例,服务端的示例代码: 

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;

/**
 * An HTTP server that sends back the content of the received HTTP request
 * in a pretty plaintext form.
 */
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();
        }
    }
}

服务端自定义的ChannelInitializer:

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslContext;

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());
    }
}

服务端的业务处理类: 

import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderUtil;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpRequest;

import static io.netty.handler.codec.http.HttpHeaderNames.*;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpVersion.*;

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();
    }
}

启动服务端后,其控制台输出内容:

Open your web browser and navigate to http://127.0.0.1:8080/

浏览器中访问上述地址,页面的输出内容: 

Netty实现HTTP服务器主要依赖于Netty包中的HttpServerCodec、HttpRequest、FullHttpResponse类。HttpServerCodec是netty针对http请求编解码的处理类,但是这些只能处理像get的请求

2、Netty实现HTTP文件下载服务器

接着我们再看一个HTTP文件服务端下载示例,Netty服务端的代码: 

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;

public class HttpFileServer {

    private static final String DEFAULT_URL = "/sources/";

    public void run(final int port, final String url) throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandl
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值