Read the article suggests looking back from the beginning of the first chapter
This series of articles
- Netty in Android application development in actual combat series (a) --- build a service and client
- Netty in Android application development in actual combat series (two) --- Encoder | Decoder | Handler of use
- Netty in Android application development in actual combat series (three) --- heartbeat processing | reconnection
- Netty in Android application development in actual combat series (four) --- stick package | unpacking process
- Netty in Android application development in actual combat series (five) --- Creating Web Services | as an HTTP server
Netty had to sigh a powerful addition to handling Socket demand, even also can create a Web service that allows Android to act as a Web server processes GET
, POST
and so on request ...
First, create a Http service
public class HttpServer {
private static final String TAG = "HttpServer";
//服务开启在的端口
public static final int PORT = 7020;
public void startHttpServer() {
try {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(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(65536));
// 处理发起的请求
pipeline.addLast(new HttpServerHandler());
}
});
//绑定服务在7020端口上
b.bind(new InetSocketAddress(PORT)).sync();
Log.d(TAG, "HTTP服务启动成功 PORT=" + PORT);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Start the HTTP service
new HttpServer().startHttpServer();
And we write the code can be found before the connection Socket added
Decoder
,Encoder
inconsistent; as used herein is a specifically packaged Netty HTTP request for the encoder and decoder
- Run effect
Second, in the HttpServerHandler
HTTP request received in the process
public class HttpServerHandler extends ChannelInboundHandlerAdapter {
private static final String TAG = "HttpServerHandler";
@Override
public void channelRead(ChannelHandlerContext ctx, Object 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();
Log.d(TAG, "==================接收到了请求==================");
Log.d(TAG, "route = " + route);
Log.d(TAG, "method = " + method);
}
}
- Here are the items I ran on the Android emulator, so you need to enter the following command in the console to do a port forwarding, so that our computers can use the browser
localhost:7020
to access to the HTTP service
//7020 就是你要转发的端口
adb forward tcp:7020 tcp:7020
- In the browser enter
localhost:7020/test
the next point of view
- Above we only received the request but the request did not return a result, which also led to the request has been unable to complete at the
请求中
state
Third, in response to the HTTP request
- Connection only needs to write
FullHttpResponse
to, the following code
ByteBuf byteBuf = Unpooled.copiedBuffer(Result.ok("请求成功").getBytes());
response(ctx, "text/json;charset=UTF-8", byteBuf, HttpResponseStatus.OK);
/**
* 响应请求结果
*
* @param ctx 返回
* @param contentType 响应类型
* @param content 消息
* @param status 状态
*/
private void response(ChannelHandlerContext ctx, String contentType, ByteBuf content, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
To which a basic HTTP service has been run up, the rest is initiated to resolve the parameters and process requests
Fourth, some examples are given below, showing how to obtain the parameters of the request and the response picture data in response to data or json
- HttpServerHandler类
public class HttpServerHandler extends ChannelInboundHandlerAdapter {
private static final String TAG = "HttpServerHandler";
@Override
public void channelRead(ChannelHandlerContext ctx, Object 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<String, Object> params = new HashMap<>();
if (method == HttpMethod.GET) {
parseGetParams(params, path);
} else if (method == HttpMethod.POST) {
parsePostParams(params, httpRequest);
} else {
//错误的请求方式
ByteBuf byteBuf = Unpooled.copiedBuffer(Result.error("不支持的请求方式").getBytes());
response(ctx, "text/json;charset=UTF-8", byteBuf, HttpResponseStatus.BAD_REQUEST);
}
Log.d(TAG, "==================接收到了请求==================");
Log.d(TAG, "route = " + route);
Log.d(TAG, "method = " + method);
Log.d(TAG, "params = " + params.toString());
handlerRequest(ctx, route, params);
}
/**
* 处理每个请求
*/
private void handlerRequest(ChannelHandlerContext ctx, String route, Map<String, Object> params) throws Exception {
switch (route) {
case "login":
ByteBuf login;
if ("admin".equals(params.get("name")) && "123".equals(params.get("psd"))) {
login = Unpooled.copiedBuffer(Result.ok("登录成功").getBytes());
} else {
login = Unpooled.copiedBuffer(Result.error("登录失败").getBytes());
}
response(ctx, "text/json;charset=UTF-8", login, HttpResponseStatus.OK);
break;
case "getImage":
//返回一张图片
ByteBuf image = getImage(new File("/storage/emulated/0/Android/data/com.azhon.nettyhttp/cache/test.jpg"));
response(ctx, "image/jpg", image, HttpResponseStatus.OK);
break;
case "json":
ByteBuf json = Unpooled.copiedBuffer(Result.ok("测试post请求成功").getBytes());
response(ctx, "text/json;charset=UTF-8", json, HttpResponseStatus.OK);
break;
default:
ByteBuf error = Unpooled.copiedBuffer(Result.error("未实现的请求地址").getBytes());
response(ctx, "text/json;charset=UTF-8", error, HttpResponseStatus.BAD_REQUEST);
break;
}
}
/**
* 解析Get请求参数
*/
private void parseGetParams(Map<String, Object> params, String path) {
//拼接成全路径好取参数
Uri uri = Uri.parse("http://127.0.0.1" + path);
Set<String> names = uri.getQueryParameterNames();
Iterator<String> iterator = names.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
params.put(key, uri.getQueryParameter(key));
}
}
/**
* 解析Post请求参数,以提交的body为json为例
*/
private void parsePostParams(Map<String, Object> params, FullHttpRequest httpRequest) throws JSONException {
ByteBuf content = httpRequest.content();
String body = content.toString(CharsetUtil.UTF_8);
JSONObject object = new JSONObject(body);
Iterator<String> keys = object.keys();
while (keys.hasNext()) {
String key = keys.next();
params.put(key, object.opt(key));
}
}
/**
* 解析调用的接口(路由地址)
*/
private String parseRoute(String path) {
if (path.contains("?")) {
String uri = path.split("\\?")[0];
return uri.substring(1);
} else {
return path.substring(1);
}
}
/**
* 返回图片
*/
private ByteBuf getImage(File file) throws Exception {
ByteBuf byteBuf = Unpooled.buffer();
FileInputStream stream = new FileInputStream(file);
int len;
byte[] buff = new byte[1024];
while ((len = stream.read(buff)) != -1) {
byteBuf.writeBytes(buff, 0, len);
}
return byteBuf;
}
/**
* 响应请求结果
*
* @param ctx 返回
* @param contentType 响应类型
* @param content 消息
* @param status 状态
*/
private void response(ChannelHandlerContext ctx, String contentType, ByteBuf content, HttpResponseStatus status) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, contentType);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
}
- Result class, the data returned json tools
public class Result {
/**
* 响应请求c成功
*/
public static String ok(String msg) {
JSONObject object = new JSONObject();
try {
object.put("code", 100);
object.put("msg", msg);
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
/**
* 响应请求失败
*/
public static String error(String msg) {
JSONObject object = new JSONObject();
try {
object.put("code", 101);
object.put("msg", msg);
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
}
Fifth, use the above to the test interface address
GET http://localhost:7020/login?name=admin&psd=123 登录
GET http://localhost:7020/getImage 获取图片
POST http://localhost:7020/json 提交json数据
- POST method used here
postman
to simulate, as follows: