public class HttpServerStart {
public static volatile boolean flag = false ;
public static void start() {
int port = 8099;
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpServerInitializer())
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true);
Channel ch = b.bind(port).sync().channel();
System.out.println("httpserver服務(wù)成功啟動(dòng),請(qǐng)打開(kāi) http://127.0.0.1:" + port);
flag = true ;
ch.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
protected void initChannel(SocketChannel socketChannel) throws Exception {
//HttpObjectAggregator HTTP 消息解碼器, 作用時(shí)將多個(gè)消息轉(zhuǎn)換為1個(gè)FullHttpRequest 或者 FullHttpResponse 對(duì)象
/**
* HttpRequestDecoder 會(huì)將每個(gè) HTTP 消息轉(zhuǎn)換為 多個(gè)消息對(duì)象
* HttpResquest / HttpResponse
* HttpContent
* LastHttpContent
*/
//將請(qǐng)求和應(yīng)答消息編碼或解碼為HTTP消息
socketChannel.pipeline().addLast(new HttpRequestDecoder());
socketChannel.pipeline().addLast(new HttpObjectAggregator(65536));// 目的是將多個(gè)消息轉(zhuǎn)換為單一的request或者response對(duì)象
socketChannel.pipeline().addLast(new HttpResponseEncoder());
socketChannel.pipeline().addLast(new ChunkedWriteHandler());//目的是支持異步大文件傳輸()
socketChannel.pipeline().addLast("file-handler", new FileServerHandler());
socketChannel.pipeline().addLast("handler", new HttpServerHandler(false));
}
}
public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
public HttpServerHandler(boolean isAutoRelease){
super(isAutoRelease);
}
protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest request) throws Exception {
try {
if(!request.decoderResult().isSuccess()){
DonkeyHttpUtil.writeResponse(request, BAD_REQUEST, channelHandlerContext);
return;
}
if(request.method() != HttpMethod.GET){
DonkeyHttpUtil.writeResponse(request, METHOD_NOT_ALLOWED, channelHandlerContext);
return;
}
DonkeyHttpUtil.writeResponse(request, OK, channelHandlerContext);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest request) throws Exception {
//request.retain();
HttpResponse response = null;
RandomAccessFile randomAccessFile = null;
try{
// 狀態(tài)為1xx的話,繼續(xù)請(qǐng)求
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(channelHandlerContext);
}
String uri = request.uri();// /digitalPlatform/common/common.js
if(!uri.endsWith(".js")
&& !uri.endsWith(".css")
&& !uri.endsWith(".html")
&& !uri.endsWith(".png")
&& !uri.endsWith(".jpg")
&& !uri.endsWith(".gif")){
channelHandlerContext.fireChannelRead(request);
return;
}
uri = uri.substring(1);
InputStream input = MyApplication.getApplication().getAssets().open(uri);
File f = new File
(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "cloudsapp"+File.separator+uri);
if (f.exists()) {
f.delete();
}else{
f.getParentFile().mkdirs();
}
f.createNewFile();
byte[] bytes = new byte[input.available()];
input.read(bytes);
OutputStream os = new FileOutputStream(f);
BufferedOutputStream bos = new BufferedOutputStream(os);
bos.write(bytes);
bos.flush();
bos.close();
try {
randomAccessFile = new RandomAccessFile(f, "r");
} catch (FileNotFoundException e) {
DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
e.printStackTrace();
return;
}
if(!f.exists() || f.isHidden()){
DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
return;
}
long fileLength = randomAccessFile.length();
response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
setContentType(response, f);
boolean keepAlive = HttpUtil.isKeepAlive(request);
if (keepAlive) {
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, fileLength);
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
channelHandlerContext.write(response);
ChannelFuture sendFileFuture = channelHandlerContext.write(new ChunkedNioFile(randomAccessFile.getChannel()), channelHandlerContext.newProgressivePromise());
// 寫(xiě)入文件尾部
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future,
long progress, long total) {
if (total < 0) { // total unknown
System.out.println("Transfer progress: " + progress);
} else {
System.out.println("Transfer progress: " + progress + " / "
+ total);
}
}
@Override
public void operationComplete(ChannelProgressiveFuture future)
throws Exception {
System.out.println("Transfer complete.");
}
});
ChannelFuture lastContentFuture = channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if (!keepAlive) {
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}
}catch (Exception e){
DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
e.printStackTrace();
}finally {
if(randomAccessFile != null){
try {
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
}else{
DonkeyHttpUtil.writeResponse(request, NOT_FOUND, channelHandlerContext);
}
}
}
public static void writeBytesToFile(InputStream is, File file) throws IOException{
FileOutputStream fos = null;
try {
byte[] data = new byte[2048];
int nbread = 0;
fos = new FileOutputStream(file);
while((nbread=is.read(data))>-1){
fos.write(data,0,nbread);
}
}
catch (Exception ex) {
Log.e("Exception",ex.getMessage());
}
finally{
if (fos!=null){
fos.close();
}
}
}
private void setContentType(HttpResponse response, File file){
//MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
if(file.getName().endsWith(".js")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/x-javascript");
}else if(file.getName().endsWith(".css")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/css; charset=UTF-8");
}else if (file.getName().endsWith(".html")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private static void send100Continue(ChannelHandlerContext ctx) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);
ctx.writeAndFlush(response);
}
}
public class DonkeyHttpUtil {
public static boolean writeResponse(FullHttpRequest request, HttpResponseStatus status, ChannelHandlerContext ctx) {
// Decide whether to close the connection or not.
boolean keepAlive = HttpUtil.isKeepAlive(request);
// Build the response object.
FullHttpResponse response = new DefaultFullHttpResponse(request.protocolVersion(), status,
Unpooled.copiedBuffer(status.toString(), CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
if (keepAlive) {
// Add 'Content-Length' header only for a keep-alive connection.
response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
// Add keep alive header as per:
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
// Encode the cookie.
String cookieString = request.headers().get(HttpHeaderNames.COOKIE);
if (cookieString != null) {
Set<io.netty.handler.codec.http.cookie.Cookie> cookies = ServerCookieDecoder.STRICT.decode(cookieString);
if (!cookies.isEmpty()) {
// Reset the cookies if necessary.
for (io.netty.handler.codec.http.cookie.Cookie cookie : cookies) {
response.headers().add(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
}
}
}
// Write the response.
ctx.write(response);
return keepAlive;
}
}