Android使用Netty搭建Web服务器
16lz
2022-07-09
在Android中使用netty可以很容易搭建一个web服务器;同时具有netty的优良特性:高性能,高可靠性,API易上手等;本篇文章主要介绍在Android中使用netty搭建web服务器的简单过程,对于一些复杂使用,复杂特性不做深究;不甚了解netty的可以先阅读此篇入门文章:Netty在Android中使用
- 目录
- 1.服务器配置及启动
- 2.实现客户端请求数据的读取:HttpServerHandler
- 3.实现数据发送
- 4.注意地方
- 5.推荐阅读
1.服务器配置及启动
- 在后台线程中执行此方法:
private void startServer() { try { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override protected void initChannel(io.netty.channel.socket.SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline = socketChannel.pipeline(); // http服务器端对request解码 pipeline.addLast(new HttpRequestDecoder()); // http服务器端对response编码 pipeline.addLast(new HttpResponseEncoder()); // 在处理POST消息体时需要加上 pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); // 处理发起的请求 pipeline.addLast(new HttpServerHandler()); //在HttpResponseEncoder序列化之前会对response对象进行HttpContentCompressor压缩 pipeline.addLast("compressor", new HttpContentCompressor()); } }); b.bind(new InetSocketAddress(PORT)).sync(); Log.d(TAG, "HTTP服务启动成功 PORT=" + PORT); } catch (Exception e) { e.printStackTrace(); } }
- 使用Http进行编解码主要添加:
// http服务器端对request解码pipeline.addLast(new HttpRequestDecoder());// http服务器端对response编码pipeline.addLast(new HttpResponseEncoder());
- 对发起的请求进行处理:(详细见#2中的实现方法)
pipeline.addLast(new HttpServerHandler());
2.实现客户端请求数据的读取:HttpServerHandler
- 详细步骤见代码
- 浏览器访问参考:
http://172.16.3.112:8080/json
http://172.16.3.112:8080/login?name=admin&psw=123456
http://172.16.3.112:8080/getImage
package me.com.testnettywebserver;import android.net.Uri;import android.util.Log;import org.json.JSONException;import org.json.JSONObject;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Set;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.ChannelFutureListener;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.DefaultFullHttpResponse;import io.netty.handler.codec.http.FullHttpRequest;import io.netty.handler.codec.http.FullHttpResponse;import io.netty.handler.codec.http.HttpHeaderNames;import io.netty.handler.codec.http.HttpMethod;import io.netty.handler.codec.http.HttpObject;import io.netty.handler.codec.http.HttpResponseStatus;import io.netty.handler.codec.http.HttpVersion;import io.netty.util.CharsetUtil;public class HttpServerHandler extends SimpleChannelInboundHandler { private static final String TAG = "HttpServerHandler"; @Override public void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception { if (!(msg instanceof FullHttpRequest)){ Log.e(TAG,"未知请求:"+msg.toString()); return; } FullHttpRequest httpRequest = (FullHttpRequest) msg; String path = httpRequest.uri(); HttpMethod method = httpRequest.method(); String route = parseRoute(path); Map params = new HashMap<>(); if (method == HttpMethod.GET){ parseGetParams(params,path); }else if (method == HttpMethod.POST){ parsePostParams(params,httpRequest); }else { ByteBuf byteBuf = Unpooled.copiedBuffer(HttpResult.error("不支持的请求方式").getBytes()); response(ctx,"text/json;charset=UTF-8",byteBuf, HttpResponseStatus.BAD_REQUEST); } Log.e(TAG,"******************接收到了请求******************"); Log.e(TAG,"method:"+method); Log.e(TAG,"route:"+route); Log.e(TAG,"params:"+params.toString()); //路由实现 handlerRequest(ctx,route,params); } private void handlerRequest(ChannelHandlerContext ctx, String route, Map params) { switch (route){ case "login": ByteBuf login; if ("admin".equals(params.get("name")) && "123456".equals(params.get("psw"))){ login = Unpooled.copiedBuffer(HttpResult.ok("登录成功").getBytes()); }else { login = Unpooled.copiedBuffer(HttpResult.error("登录失败").getBytes()); } response(ctx,"text/json;charset=UTF-8",login,HttpResponseStatus.OK); break; case "getImage": ByteBuf imgBuf = getImage(new File("/storage/emulated/0/MagazineUnlock/1.jpg")); response(ctx,"image/jpeg",imgBuf,HttpResponseStatus.OK); break; case "json": ByteBuf byteBuf = Unpooled.copiedBuffer(HttpResult.ok("测试post请求成功").getBytes()); response(ctx,"text/json;charset=UTF-8",byteBuf,HttpResponseStatus.OK); break; default: ByteBuf buf = Unpooled.copiedBuffer(HttpResult.error("未实现的请求地址").getBytes()); response(ctx,"text/json;charset=UTF-8",buf,HttpResponseStatus.BAD_REQUEST); break; } } private ByteBuf getImage(File file) { ByteBuf byteBuf = Unpooled.buffer(); try { FileInputStream fileInputStream = new FileInputStream(file); int len; byte[] buf = new byte[1024]; while ((len = fileInputStream.read(buf)) != -1){ byteBuf.writeBytes(buf,0,len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return byteBuf; } private void parsePostParams(Map params, FullHttpRequest httpRequest) { ByteBuf content = httpRequest.content(); String body = content.toString(CharsetUtil.UTF_8); try { JSONObject jsonObject = new JSONObject(body); Iterator iterator = jsonObject.keys(); while (iterator.hasNext()){ String key = iterator.next(); params.put(key,jsonObject.opt(key)); } } catch (JSONException e) { e.printStackTrace(); } } private void parseGetParams(Map params, String path) { Uri uri = Uri.parse("http://172.16.0.1"+path); Set names = uri.getQueryParameterNames(); Iterator iterator = names.iterator(); while (iterator.hasNext()){ String key = iterator.next(); params.put(key,uri.getQueryParameter(key)); } } private void response(ChannelHandlerContext ctx, String type, ByteBuf byteBuf, HttpResponseStatus status) { FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,status,byteBuf); httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,type); ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE); } /** * 解析调用的接口(路由地址) */ private String parseRoute(String path) { if (path.contains("?")) { String uri = path.split("\\?")[0]; return uri.substring(1); } else { return path.substring(1); } }}
3.实现数据发送
private void response(ChannelHandlerContext ctx, String type, ByteBuf byteBuf, HttpResponseStatus status) { FullHttpResponse httpResponse = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,status,byteBuf); httpResponse.headers().set(HttpHeaderNames.CONTENT_TYPE,type); ctx.writeAndFlush(httpResponse).addListener(ChannelFutureListener.CLOSE); }
4.注意地方
- 添加权限
- 跨域解决(跨域原因是:浏览器的同源策略,前端使用了不同源的url访问服务器)
解决方法:在Response header中添加:
httpResponse.headers().add("Access-Control-Allow-Origin", "*");httpResponse.headers().add("Access-Control-Allow-Methods", "GET, POST, PUT,DELETE,OPTIONS,PATCH");httpResponse.headers().add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
5.推荐阅读
- Netty在Android中的常见使用
- 在Android中使用Netty接收Http文件上传
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- 箭头函数的基础使用
- NPM 和webpack 的基础使用
- Python list sort方法的具体使用
- 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
- python list.sort()根据多个关键字排序的方法实现
- android EditText设置不可写
- Android(安卓)拨号器的简单实现
- android 使用html5作布局文件: webview跟javascript交互