根据netty一个官方例子改编
//html文件位置 public class Config { public static String getRealPath(String uri) { StringBuilder sb=new StringBuilder("E:/htmlDemo"); sb.append(uri); if (!uri.endsWith("/")) { sb.append('/'); } return sb.toString(); } }
//根据url获取html资源 public class HttpServerHandler2 extends SimpleChannelInboundHandler<Object> { private HttpRequest request; private boolean readingChunks; private static final HttpDataFactory factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE); //Disk private HttpPostRequestDecoder decoder; @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (decoder != null) { decoder.cleanFiles(); } } @Override public void channelReadComplete(ChannelHandlerContext ctx){ ctx.flush(); System.out.println("channelReadComplete"); } @Override protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof HttpRequest) { HttpRequest request = this.request = (HttpRequest) msg; if (HttpHeaderUtil.is100ContinueExpected(request)) { send100Continue(ctx); } HttpHeaders headers = request.headers(); if (!headers.isEmpty()) { for (Map.Entry<CharSequence, CharSequence> h: headers) { CharSequence key = h.getKey(); CharSequence value = h.getValue(); } } QueryStringDecoder queryStringDecoder = new QueryStringDecoder(request.uri()); Map<String, List<String>> params = queryStringDecoder.parameters(); if (!params.isEmpty()) { for (Entry<String, List<String>> p: params.entrySet()) { String key = p.getKey(); List<String> vals = p.getValue(); for (String val : vals) { } } } try { decoder = new HttpPostRequestDecoder(factory, request); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); //writeResponse(ctx.channel()); ctx.channel().close(); return; } readingChunks = HttpHeaderUtil.isTransferEncodingChunked(request); System.out.println("Is Chunked: " + readingChunks + "\r\n"); System.out.println("IsMultipart: " + decoder.isMultipart() + "\r\n"); if (readingChunks) { // Chunk version System.out.println("Chunks: "); readingChunks = true; } } if(decoder != null){ if (msg instanceof HttpContent) { // New chunk is received HttpContent chunk = (HttpContent) msg; try { decoder.offer(chunk); } catch (ErrorDataDecoderException e1) { e1.printStackTrace(); //writeResponse(ctx.channel()); ctx.channel().close(); return; } System.out.println('o'); //readHttpDataChunkByChunk(); // example of reading only if at the end if (chunk instanceof LastHttpContent) { String uri = this.request.uri(); System.out.println("-----------------------------------------------------------------"); System.out.println("uri:"+uri); System.out.println("-----------------------------------------------------------------"); writeResponse(ctx, uri); readingChunks = false; reset(); } } }else { writeResponse(ctx, "/"); } } private void reset() { request = null; // destroy the decoder to release all resources decoder.destroy(); decoder = null; } private void writeResponse(ChannelHandlerContext ctx, String uri) { // 解析Connection首部,判断是否为持久连接 boolean keepAlive = HttpHeaderUtil.isKeepAlive(request); // Build the response object. FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); response.setStatus(HttpResponseStatus.OK); // 服务端可以通过location首部将客户端导向某个资源的地址。 // response.addHeader("Location", uri); if (keepAlive) { // Add 'Content-Length' header only for a keep-alive connection. response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); } // 得到客户端的cookie信息,并再次写到客户端 String cookieString = request.headers().getAndConvert(HttpHeaderNames.COOKIE); if (cookieString != null) { Set<Cookie> cookies = ServerCookieDecoder.decode(cookieString); if (!cookies.isEmpty()) { // Reset the cookies if necessary. for (Cookie cookie: cookies) { response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode(cookie)); } } } else { // Browser sent no cookie. Add some. response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode("key1", "value1")); response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.encode("key2", "value2")); } //文件路径 final String path = (Config.getRealPath(uri)); File localFile = new File(path); // 如果文件隐藏或者不存在 if (localFile.isHidden() || !localFile.exists()) { // 逻辑处理 System.out.println("如果文件隐藏或者不存在"); sendError(ctx, NOT_FOUND); return; } // 如果请求路径为目录 if (localFile.isDirectory()) { // 逻辑处理 System.out.println("如果请求路径为目录"); return; } RandomAccessFile raf = null; try { raf = new RandomAccessFile(localFile, "r"); long fileLength = raf.length(); response.headers().setLong(HttpHeaderNames.CONTENT_LENGTH, fileLength); Channel ch = ctx.channel(); ch.write(response); // 这里又要重新温习下http的方法,head方法与get方法类似,但是服务器在响应中只返回首部,不会返回实体的主体部分 if (!request.method().equals(HttpMethod.HEAD)) { System.out.println("读文件"); ch.write(new ChunkedFile(raf, 0, fileLength, 8192));//8kb } } catch (Exception e2) { e2.printStackTrace(); } finally { if (keepAlive) { response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes()); } if (!keepAlive) { ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE); } } } private void send100Continue(ChannelHandlerContext ctx) { FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE); ctx.write(response); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } }
//服务运行类 public class HttpServer { public void run(final int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast("http-decoder", new HttpRequestDecoder()); ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536)); ch.pipeline().addLast("http-encoder", new HttpResponseEncoder()); ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); ch.pipeline().addLast("handler", new HttpServerHandler()); } }); ChannelFuture future = b.bind("192.168.1.10", port).sync(); System.out.println("HTTP服务器启动,网址是 : " + "http://192.168.1.10:" + port); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new HttpServer().run(8080); }