• java构建简单的HTTP服务器


    使用Java技术构建Web应用时, 我们通常离不开tomcat和jetty之类的servlet容器,这些Web服务器功能强大,性能强劲,深受欢迎,是运行大型Web应用的必备神器。

     

    虽然Java的设计初衷就是用来开发大型应用的,然而有时候我们开发的程序只是简单的小型应用,对于功能的需求和性能的要求并不高, 可能仅仅就几百行甚至几十行代码,这个时候使用tomcat之类的Web服务器去运行就显得有点大材小用了。 比如说只是将数据库中的数据读出来转换成JSON,以Web服务的形式吐给调用方这样的阉割型Web应用。 如下图所示

     

    二、最简单的Java Http服务器

     

    其实在jdk中已经内置了用于此类简单Web应用构建需求的类库了,sun公司提供的 com.sun.net.httpserver 包就是用来帮助我们解决这类问题的

    复制代码
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.HttpServer;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.InetSocketAddress;
    
    public class Main {
    
        public static void main(String[] arg) throws Exception {
            HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
            server.createContext("/test", new TestHandler());
            server.start();
        }
    
        static  class TestHandler implements HttpHandler{
            @Override
            public void handle(HttpExchange exchange) throws IOException {
                String response = "hello world";
                exchange.sendResponseHeaders(200, 0);
                OutputStream os = exchange.getResponseBody();
                os.write(response.getBytes());
                os.close();
            }
        }
    }
    复制代码

    如上代码清单所示, 仅仅几行代码就可以构建一个五脏俱全的Web应用了。执行代码,在浏览器地址栏里代开链接

    http://localhost:8001/test

    就能运行这个段程序,输入的结果为helloworld

     

    三、获得外部数据

     

    那在这个程序中如何获取到外部传递过来的数据呢?比如说URL上的查询字符串,POST提交的数据等,其实也很简单 

    复制代码
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.HttpServer;
    import org.apache.commons.io.IOUtils;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.InetSocketAddress;
    import java.net.URLDecoder;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Main {
    
        public static void main(String[] arg) throws Exception {
            HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
            server.createContext("/test", new TestHandler());
            server.start();
        }
    
        static class TestHandler implements HttpHandler{
            @Override
            public void handle(HttpExchange exchange) {
                String response = "hello world";
    
                try{
                    //获得查询字符串(get)
                    String queryString =  exchange.getRequestURI().getQuery();
                    Map<String,String> queryStringInfo = formData2Dic(queryString);
                    //获得表单提交数据(post)
                    String postString = IOUtils.toString(exchange.getRequestBody());
                    Map<String,String> postInfo = formData2Dic(postString);
    
                    exchange.sendResponseHeaders(200,0);
                    OutputStream os = exchange.getResponseBody();
                    os.write(response.getBytes());
                    os.close();
                }catch (IOException ie) {
    
                } catch (Exception e) {
    
                }
            }
        }
    
        public static Map<String,String> formData2Dic(String formData ) {
            Map<String,String> result = new HashMap<>();
            if(formData== null || formData.trim().length() == 0) {
                return result;
            }
            final String[] items = formData.split("&");
            Arrays.stream(items).forEach(item ->{
                final String[] keyAndVal = item.split("=");
                if( keyAndVal.length == 2) {
                    try{
                        final String key = URLDecoder.decode( keyAndVal[0],"utf8");
                        final String val = URLDecoder.decode( keyAndVal[1],"utf8");
                        result.put(key,val);
                    }catch (UnsupportedEncodingException e) {}
                }
            });
            return result;
        }
    }
    复制代码

    上面的代码清单标识了实现的方法。

     

    注意,要保证上面代码编译通过, 需要引入commons-io.jar,此包中提供将InputStream转换成String的方法。

     

     

    四、并发处理

     

    com.sun.net.httpserver似乎默认不支持同时处理多个请求,一旦有并行的请求涌入,需要排队等待程序处理,导致Web程序响应卡顿。自定义实现的方法也很简单,为每个请求开一个新的线程处理即可, 如下代码清单所示

     

    复制代码
    import com.sun.net.httpserver.HttpExchange;
    import com.sun.net.httpserver.HttpHandler;
    import com.sun.net.httpserver.HttpServer;
    import org.apache.commons.io.IOUtils;
    
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.InetSocketAddress;
    import java.net.URLDecoder;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.Map;
    
    public class Main {
    
        public static void main(String[] arg) throws Exception {
            HttpServer server = HttpServer.create(new InetSocketAddress(8001), 0);
            server.createContext("/test", new TestHandler());
            server.start();
        }
    
        static class TestHandler implements HttpHandler{
            @Override
            public void handle(HttpExchange exchange) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try{
                            String response = "hello world";
                            //获得查询字符串(get)
                            String queryString =  exchange.getRequestURI().getQuery();
                            Map<String,String> queryStringInfo = formData2Dic(queryString);
                            //获得表单提交数据(post)
                            String postString = IOUtils.toString(exchange.getRequestBody());
                            Map<String,String> postInfo = formData2Dic(postString);
    
                            exchange.sendResponseHeaders(200,0);
                            OutputStream os = exchange.getResponseBody();
                            os.write(response.getBytes());
                            os.close();
                        }catch (IOException ie) {
                            ie.printStackTrace();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        }
    
        public static Map<String,String> formData2Dic(String formData ) {
            Map<String,String> result = new HashMap<>();
            if(formData== null || formData.trim().length() == 0) {
                return result;
            }
            final String[] items = formData.split("&");
            Arrays.stream(items).forEach(item ->{
                final String[] keyAndVal = item.split("=");
                if( keyAndVal.length == 2) {
                    try{
                        final String key = URLDecoder.decode( keyAndVal[0],"utf8");
                        final String val = URLDecoder.decode( keyAndVal[1],"utf8");
                        result.put(key,val);
                    }catch (UnsupportedEncodingException e) {}
                }
            });
            return result;
        }
    }
    复制代码

    五、优点

     

    Java内置Web服务器在功能、性能、稳定等方面是无法和tomcat和jetty之类的专业Web服务器相比的, 它的优点主要是开发和部署方便简单, 把程序代码编译成jar包后,丢到装有jvm的服务器上, 直接运行就可以了,省去了安装相关的软件、依赖, 配置复杂的环境等工作量。

     

    但是, 在一些各方面要求都比较高的生产环境下,还是建议使用专门的Web服务器,毕竟它们久经考验,能满足所有功能需求,并且出问题的几率低。 

    知乎:https://www.zhihu.com/people/aspwebchh

    github:https://github.com/aspwebchh

    email: aspwebchh@gmail.com

  • 相关阅读:
    BZOJ2303:[APIO2011]方格染色(并查集)
    BZOJ1116:[POI2008]CLO(并查集)
    BZOJ4011:[HNOI2015]落忆枫音(DP,拓扑排序)
    洛谷1387 最大正方形
    洛谷 P1858 多人背包
    vijos 1085 Sunnypig闯三角关
    vijos 1030 重叠的方框
    codevs 1001 舒适的路线 WK
    1266. [NOIP2012] 借教室
    codevs 2370 小机房的树
  • 原文地址:https://www.cnblogs.com/qiu18359243869/p/11136724.html
Copyright © 2020-2023  润新知