Netty in Android application development in actual combat series (five) --- Creating Web Services | as an HTTP server

Read the article suggests looking back from the beginning of the first chapter

This series of articles

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, POSTand 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, Encoderinconsistent; as used herein is a specifically packaged Netty HTTP request for the encoder and decoder

  • Run effect
    Here Insert Picture Description

Second, in the HttpServerHandlerHTTP 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:7020to access to the HTTP service
//7020 就是你要转发的端口
adb forward tcp:7020 tcp:7020
  • In the browser enter localhost:7020/testthe next point of view
    Here Insert Picture Description
  • 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
    Here Insert Picture Description

Third, in response to the HTTP request

  • Connection only needs to write FullHttpResponseto, 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 postmanto simulate, as follows:
    Here Insert Picture Description

Sixth, operating results

Here Insert Picture Description

Netty under general use is still very easy to create a Http service, interested students can try; code has been posted in the article do not upload the Demo (Demo also download upload integration emmmm ...)

Published 140 original articles · won praise 546 · views 540 000 +

Guess you like

Origin blog.csdn.net/a_zhon/article/details/101226878