仅使用Java SE API的Java中的简单HTTP服务器


333

有没有一种方法可以仅使用Java SE API在Java中创建一个非常基本的HTTP服务器(仅支持GET / POST),而无需编写代码来手动解析HTTP请求和手动格式化HTTP响应?Java SE API将HTTP客户端功能很好地封装在HttpURLConnection中,但是HTTP服务器功能是否类似?

明确地说,我在网上看到的许多ServerSocket示例存在的问题是,它们执行自己的请求解析/响应格式和错误处理,这很繁琐,容易出错,而且不太可能全面,由于这些原因,我正努力避免这种情况。

作为我要避免的手动HTTP操作的示例:

http://java.sun.com/developer/technicalArticles/Networking/Webserver/WebServercode.html


3
嗯...简短的回答是不。如果您想要某种无需手动编写http头即可处理发布和获取请求的东西,则可以使用servlet。但这就是java ee。如果您不想使用类似的方法,那么套接字和手动解析是我所知道的唯一其他选择。
马特·菲利普斯

3
我知道这不是SO的精神,但是我敦促您重新考虑您对Java EE API的厌恶。正如一些答案提到的那样,有一些非常简单的实现,例如Jetty,允许您将Web服务器嵌入独立的应用程序中,同时仍然利用servlet api。如果您出于某些原因绝对不能使用Java EE API,请忽略我的评论:-)
Chris Thompson 2010年

1
“ Servlet”不是真正的“ Java EE”。它们只是编写可被周围的应用程序调用以响应消息活动(这些日子通常是HTTP请求)的插件的一种方式。提供“仅使用Java SE API”的servlet托管环境正是Jetty和Tomcat所做的。当然,您可能希望消除不必要的复杂性,但随后可能需要确定GET / POST的允许属性和配置的子集。除了特殊的安全性/嵌入式问题外,这通常不值得。
David Tonhofer

1
在做出决定之前,可能值得浏览一下HTTP服务器列表。java-source.net/open-source/web-servers
威胁

Answers:


469

从Java SE 6开始,Sun Oracle JRE中内置了HTTP服务器。该com.sun.net.httpserver包的摘要概述了参与类和包含的例子。

这是一个从他们的文档中复制的启动示例(尽管如此,所有尝试编辑它的人都可以使用,因为这是一段难看的代码,请不要这样做,这是一个复制粘贴,不是我的,此外,除非更改了它们,否则切勿编辑引号在原始来源中)。您可以只复制'n'paste'n'在Java 6+上运行它。

package com.stackoverflow.q3732109;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Test {

    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        server.setExecutor(null); // creates a default executor
        server.start();
    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

}

应当注意的response.length()是,他们的示例中的那部分不好,应该已经response.getBytes().length。即使这样,该getBytes()方法也必须显式指定字符集,然后在响应头中指定该字符集。las,尽管误导了初学者,但毕竟这只是一个基本的启动示例。

执行它并转到http:// localhost:8000 / test,您将看到以下响应:

这是回应


关于使用com.sun.*类,请注意,这与某些开发人员的想法相反,众所周知的FAQ 为什么开发人员不应编写调用“ sun”程序包的程序绝对不禁止这样做。该FAQ 与Oracle JRE内部使用的sun.*软件包(例如sun.misc.BASE64Encoder)有关(因此,当您在其他JRE上运行应用程序时,它会杀死您的应用程序),而不是com.sun.*软件包。Sun / Oracle像其他公司一样,也像其他公司一样,也在Java SE API之上自行开发软件。com.sun.*仅在涉及某些Java API 的实现时才鼓励使用(但不禁止使用)类,例如GlassFish(Java EE impl),Mojarra(JSF impl),Jersey(JAX-RS impl)等。


19
@Waldheinz:像作为@Software你混淆sun.*使用com.sun.*。例如,您看到sun.*API的任何文档吗?在这里查看:java.sun.com/products/jdk/faq/faq-sun-packages.html它能说明什么com.sun.*吗?该com.sun.*只是用来为自己的公共软件,这是不是Java API的一部分。他们像其他公司一样,在Java API之上开发软件。
BalusC

4
我认为这是在集成测试案例中使用的非常不错的http服务器。感谢您的提示!
安德烈亚斯·彼得森

13
如果您使用的是Eclipse并收到诸如“访问限制:由于必需的库的限制而无法访问HttpExchange类型的错误”之类的错误,stackoverflow.com/ a/10642163会告诉您如何禁用该访问检查。
Samuli Pahaoja 2013年

13
FWIW也存在于OpenJDK中。
Jason C

6
此处引用的类@jdk.Exported在OpenJDK源代码中进行了标记,这意味着该API被认为是公共的,并且将在Java 9上可用(com.sun.*由于Project Jigsaw,某些其他软件包将变得不可用)。
2015年

42

NanoHttpd

“ NanoHTTPD是一种轻量级HTTP服务器,专为嵌入其他应用程序而设计,已根据经过修改的BSD许可证发布。

它正在Github上开发,并使用Apache Maven进行构建和单元测试”


4
一个警告:NanoHTTPD可能没有针对树走攻击的保护-您应该检查它是否将在公共地址上使用。我GET /../../blahblah http/1.1所说的攻击是指发出类似请求的请求,服务器走到网站根目录之上,进入系统文件区域,提供可用于破坏或远程攻击系统的文件,例如密码文件。
劳伦斯·多尔

7
这似乎是固定的。当前版本会生成403 if(uri.startsWith(“ ..”)|| uri.endsWith(“ ..”)|| uri.indexOf(“ ../”)> = 0)。
Lena Schimmel,2012年

5
我不明白这是对这个问题的答案。
kimathie

28

com.sun.net.httpserver解决方案是不能跨越的JRE便携。最好使用javax.xml.ws中的官方webservices API 引导最小的HTTP服务器...

import java.io._
import javax.xml.ws._
import javax.xml.ws.http._
import javax.xml.transform._
import javax.xml.transform.stream._

@WebServiceProvider
@ServiceMode(value=Service.Mode.PAYLOAD) 
class P extends Provider[Source] {
  def invoke(source: Source) = new StreamSource( new StringReader("<p>Hello There!</p>"));
}

val address = "http://127.0.0.1:8080/"
Endpoint.create(HTTPBinding.HTTP_BINDING, new P()).publish(address)

println("Service running at "+address)
println("Type [CTRL]+[C] to quit!")

Thread.sleep(Long.MaxValue)

编辑:这实际上有效!上面的代码看起来像Groovy之类。这是我测试过的Java翻译:

import java.io.*;
import javax.xml.ws.*;
import javax.xml.ws.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;

@WebServiceProvider
@ServiceMode(value = Service.Mode.PAYLOAD)
public class Server implements Provider<Source> {

    public Source invoke(Source request) {
        return  new StreamSource(new StringReader("<p>Hello There!</p>"));
    }

    public static void main(String[] args) throws InterruptedException {

        String address = "http://127.0.0.1:8080/";
        Endpoint.create(HTTPBinding.HTTP_BINDING, new Server()).publish(address);

        System.out.println("Service running at " + address);
        System.out.println("Type [CTRL]+[C] to quit!");

        Thread.sleep(Long.MAX_VALUE);
    }
}

1
+1便于携带。太糟糕了,您不能按原样设置响应内容类型text/xml
icza 2014年

1
我认为您可以做到<code> class Server实现Provider <DataSource> {</ code> ... ...,然后在DataSource的<code> getContentType()</ code>方法中指定Content-Type。此外,您还可以注入WebServiceContext:<code> @Resource WebServiceContext ctx; </ code>来设置其他标头和读取请求参数。不幸的是,通过WebServiceContext设置内容类型无效。
gruenewa 2014年

4
您能否解释为什么com.sun.net.HttpServer无法跨JRE移植?
javabeangrinder

3
不,我不这么认为。它不适用于IBM的Java实现,也可能不适用于其他实现。即使现在可以使用,也可以更改内部API。为什么不只使用官方API?
gruenewa 2014年

1
此链接:docs.oracle.com/javase/9​​/docs/api/java.xml.ws-summary.html说,自从Java 9. java.xml.ws模块已经过时
埃雷尔西格尔-Halevi

23

我喜欢这个问题,因为这是一个不断创新的领域,总是需要一台轻型服务器,尤其是在谈论小型设备中的嵌入式服务器时。我认为答案分为两大类。

  1. 瘦服务器:由服务器处理的静态内容,具有最少的处理,上下文或会话处理。
  2. 小型服务器:表面上具有许多类似httpD的服务器质量,并且占用的空间尽可能小。

虽然我可能认为HTTP库(如JettyApache Http ComponentsNetty)和其他库更像是原始HTTP处理工具。标签是非常主观的,并且取决于您要求为小型站点提供的内容。我本着问题的精神,特别是关于...的评论作出区分。

  • “ ...无需编写代码即可手动解析HTTP请求并手动设置HTTP响应格式...”

这些原始工具可让您做到这一点(如其他答案所述)。他们并没有真正采用现成的制造轻型,嵌入式或小型服务器的风格。小型服务器可以为您提供与功能齐全的Web服务器(例如Tomcat)类似的功能,而不会花哨的时间,小巧的性能和99%的性能。瘦服务器似乎比原始措辞更接近原始措辞,也许具有有限的子集功能,但足以使您90%的时间看起来不错。我的原始想法是让我在没有额外设计和编码的情况下,看起来75%-89%的时间看起来不错。我认为,如果/当您达到WAR文件的级别时,我们已经将bonsi服务器的“小”字样留给了看起来像大型服务器的所有东西都变小了。

瘦服务器选项

小型服务器选项:

  • Spark Java ...可以使用很多辅助构造(如过滤器,模板等)来实现美好的事情。
  • MadVoc ...旨在成为盆景,很可能是这样;-)

在考虑的其他事项中,我将包括身份验证,验证,国际化,使用FreeMaker等工具或其他模板工具来呈现页面输出。否则,管理HTML编辑和参数化可能会使使用HTTP看起来像noughts-n-crosses。自然,这一切都取决于您需要具备的灵活性。如果它是菜单驱动的传真机,则可能非常简单。交互越多,您的框架就需要 ”。好问题,祝你好运!


21

看看“ Jetty” Web服务器Jetty。一流的开源软件,似乎可以满足您的所有要求。

如果您坚持自己动手,请查看“ httpMessage”类。


我认为码头API取决于servlet。
无可争议的2010年

4
@Irreputable:不,Jetty是一个高度模块化的Web服务器,它具有一个servlet容器作为其可选模块之一。
劳伦斯·多尔

“是服务器功能的模拟” –是的是“ Servlet” API。servlet容器调用您的类已经解析了头之后,饼干等
詹姆斯-安德森

1
仅作记录-Jetty带有自己的Servlet API实现,并且可以与Java SE很好地配合使用
James Anderson

4
码头太大,在实际生产使用成为可能之前,学习曲线太多。
2014年

18

曾几何时,我一直在寻找类似的东西-一种轻巧而功能齐全的HTTP服务器,可以轻松嵌入和自定义。我发现了两种潜在的解决方案:

  • 并非轻巧或简单的完整服务器(对于轻量级的极端定义。)
  • 真正的轻量级服务器不是完全HTTP服务器,而是美化了ServerSocket示例,这些示例甚至都不是远程RFC兼容的,并且不支持通常需要的基本功能。

所以...我着手编写JLHTTP-Java轻量级HTTP服务器

您可以将其作为单个(如果相当长的话)源文件或不依赖项的〜50K jar(剥离后为〜35K)嵌入任何项目中。它努力做到与RFC兼容,并包含大量文档和许多有用的功能,同时将膨胀降至最低。

功能包括:虚拟主机,从磁盘提供文件,通过标准mime.types文件进行mime类型映射,目录索引生成,欢迎文件,对所有HTTP方法的支持,条件ETag和If- *标头支持,分块传输编码,gzip / deflate压缩,基本HTTPS(由JVM提供),部分内容(下载继续),用于文件上传的多部分/表单数据处理,通过API或注释的多个上下文处理程序,参数解析(查询字符串或x-www-form-urlencoded)身体)等

我希望其他人觉得它有用:-)


主要方法是基本用法的一个很好的例子,并且FAQ涉及许多细节。如果您有改进现有文档的建议,请随时直接与我联系!
amichair



8

只需几行代码,就可以创建一个httpserver,它仅使用JDK和servlet api提供对J2EE servlet的基本支持。

我发现这对于单元测试servlet非常有用,因为它的启动速度比其他轻量级容器快得多(我们使用码头生产)。

大多数非常轻量级的httpserver不提供对servlet的支持,但是我们需要它们,因此我想与您分享。

下面的示例提供基本的servlet支持,或者为尚未实现的东西提供throws和UnsupportedOperationException。它使用com.sun.net.httpserver.HttpServer获得基本的HTTP支持。

import java.io.*;
import java.lang.reflect.*;
import java.net.InetSocketAddress;
import java.util.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

@SuppressWarnings("deprecation")
public class VerySimpleServletHttpServer {
    HttpServer server;
    private String contextPath;
    private HttpHandler httpHandler;

    public VerySimpleServletHttpServer(String contextPath, HttpServlet servlet) {
        this.contextPath = contextPath;
        httpHandler = new HttpHandlerWithServletSupport(servlet);
    }

    public void start(int port) throws IOException {
        InetSocketAddress inetSocketAddress = new InetSocketAddress(port);
        server = HttpServer.create(inetSocketAddress, 0);
        server.createContext(contextPath, httpHandler);
        server.setExecutor(null);
        server.start();
    }

    public void stop(int secondsDelay) {
        server.stop(secondsDelay);
    }

    public int getServerPort() {
        return server.getAddress().getPort();
    }

}

final class HttpHandlerWithServletSupport implements HttpHandler {

    private HttpServlet servlet;

    private final class RequestWrapper extends HttpServletRequestWrapper {
        private final HttpExchange ex;
        private final Map<String, String[]> postData;
        private final ServletInputStream is;
        private final Map<String, Object> attributes = new HashMap<>();

        private RequestWrapper(HttpServletRequest request, HttpExchange ex, Map<String, String[]> postData, ServletInputStream is) {
            super(request);
            this.ex = ex;
            this.postData = postData;
            this.is = is;
        }

        @Override
        public String getHeader(String name) {
            return ex.getRequestHeaders().getFirst(name);
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            return new Vector<String>(ex.getRequestHeaders().get(name)).elements();
        }

        @Override
        public Enumeration<String> getHeaderNames() {
            return new Vector<String>(ex.getRequestHeaders().keySet()).elements();
        }

        @Override
        public Object getAttribute(String name) {
            return attributes.get(name);
        }

        @Override
        public void setAttribute(String name, Object o) {
            this.attributes.put(name, o);
        }

        @Override
        public Enumeration<String> getAttributeNames() {
            return new Vector<String>(attributes.keySet()).elements();
        }

        @Override
        public String getMethod() {
            return ex.getRequestMethod();
        }

        @Override
        public ServletInputStream getInputStream() throws IOException {
            return is;
        }

        @Override
        public BufferedReader getReader() throws IOException {
            return new BufferedReader(new InputStreamReader(getInputStream()));
        }

        @Override
        public String getPathInfo() {
            return ex.getRequestURI().getPath();
        }

        @Override
        public String getParameter(String name) {
            String[] arr = postData.get(name);
            return arr != null ? (arr.length > 1 ? Arrays.toString(arr) : arr[0]) : null;
        }

        @Override
        public Map<String, String[]> getParameterMap() {
            return postData;
        }

        @Override
        public Enumeration<String> getParameterNames() {
            return new Vector<String>(postData.keySet()).elements();
        }
    }

    private final class ResponseWrapper extends HttpServletResponseWrapper {
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        final ServletOutputStream servletOutputStream = new ServletOutputStream() {

            @Override
            public void write(int b) throws IOException {
                outputStream.write(b);
            }
        };

        private final HttpExchange ex;
        private final PrintWriter printWriter;
        private int status = HttpServletResponse.SC_OK;

        private ResponseWrapper(HttpServletResponse response, HttpExchange ex) {
            super(response);
            this.ex = ex;
            printWriter = new PrintWriter(servletOutputStream);
        }

        @Override
        public void setContentType(String type) {
            ex.getResponseHeaders().add("Content-Type", type);
        }

        @Override
        public void setHeader(String name, String value) {
            ex.getResponseHeaders().add(name, value);
        }

        @Override
        public javax.servlet.ServletOutputStream getOutputStream() throws IOException {
            return servletOutputStream;
        }

        @Override
        public void setContentLength(int len) {
            ex.getResponseHeaders().add("Content-Length", len + "");
        }

        @Override
        public void setStatus(int status) {
            this.status = status;
        }

        @Override
        public void sendError(int sc, String msg) throws IOException {
            this.status = sc;
            if (msg != null) {
                printWriter.write(msg);
            }
        }

        @Override
        public void sendError(int sc) throws IOException {
            sendError(sc, null);
        }

        @Override
        public PrintWriter getWriter() throws IOException {
            return printWriter;
        }

        public void complete() throws IOException {
            try {
                printWriter.flush();
                ex.sendResponseHeaders(status, outputStream.size());
                if (outputStream.size() > 0) {
                    ex.getResponseBody().write(outputStream.toByteArray());
                }
                ex.getResponseBody().flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                ex.close();
            }
        }
    }

    public HttpHandlerWithServletSupport(HttpServlet servlet) {
        this.servlet = servlet;
    }

    @SuppressWarnings("deprecation")
    @Override
    public void handle(final HttpExchange ex) throws IOException {
        byte[] inBytes = getBytes(ex.getRequestBody());
        ex.getRequestBody().close();
        final ByteArrayInputStream newInput = new ByteArrayInputStream(inBytes);
        final ServletInputStream is = new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return newInput.read();
            }
        };

        Map<String, String[]> parsePostData = new HashMap<>();

        try {
            parsePostData.putAll(HttpUtils.parseQueryString(ex.getRequestURI().getQuery()));

            // check if any postdata to parse
            parsePostData.putAll(HttpUtils.parsePostData(inBytes.length, is));
        } catch (IllegalArgumentException e) {
            // no postData - just reset inputstream
            newInput.reset();
        }
        final Map<String, String[]> postData = parsePostData;

        RequestWrapper req = new RequestWrapper(createUnimplementAdapter(HttpServletRequest.class), ex, postData, is);

        ResponseWrapper resp = new ResponseWrapper(createUnimplementAdapter(HttpServletResponse.class), ex);

        try {
            servlet.service(req, resp);
            resp.complete();
        } catch (ServletException e) {
            throw new IOException(e);
        }
    }

    private static byte[] getBytes(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        while (true) {
            int r = in.read(buffer);
            if (r == -1)
                break;
            out.write(buffer, 0, r);
        }
        return out.toByteArray();
    }

    @SuppressWarnings("unchecked")
    private static <T> T createUnimplementAdapter(Class<T> httpServletApi) {
        class UnimplementedHandler implements InvocationHandler {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                throw new UnsupportedOperationException("Not implemented: " + method + ", args=" + Arrays.toString(args));
            }
        }

        return (T) Proxy.newProxyInstance(UnimplementedHandler.class.getClassLoader(),
                new Class<?>[] { httpServletApi },
                new UnimplementedHandler());
    }
}

这缺少ServletOutputStream和ServletInputStream上的某些方法
HomeIsWhereThePcIs

较新版本的servlet api,适用于3.0及以下版本。只需在示例中根据需要添加丢失的方法即可
f.carlsen

6

我强烈建议您研究Simple,尤其是在您不需要Servlet功能而只需访问请求/响应对象的情况下。如果需要REST,则可以将Jersey置于其之上,如果需要输出HTML或类似内容,则可以使用Freemarker。我真的很喜欢您可以通过这种组合执行的操作,而且学习的API相对较少。


+1。我喜欢Simple背后的想法。但是,尝试使用HTTPS时会出现问题,因为Mamba取消了Simple的“可嵌入”功能。
威胁

6

该代码比我们的代码更好,您只需要添加2个库:javax.servelet.jarorg.mortbay.jetty.jar

班级码头:

package jetty;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHttpContext;

public class Jetty {

    public static void main(String[] args) {
        try {
            Server server = new Server();
            SocketListener listener = new SocketListener();      

            System.out.println("Max Thread :" + listener.getMaxThreads() + " Min Thread :" + listener.getMinThreads());

            listener.setHost("localhost");
            listener.setPort(8070);
            listener.setMinThreads(5);
            listener.setMaxThreads(250);
            server.addListener(listener);            

            ServletHttpContext context = (ServletHttpContext) server.getContext("/");
            context.addServlet("/MO", "jetty.HelloWorldServlet");

            server.start();
            server.join();

        /*//We will create our server running at http://localhost:8070
        Server server = new Server();
        server.addListener(":8070");

        //We will deploy our servlet to the server at the path '/'
        //it will be available at http://localhost:8070
        ServletHttpContext context = (ServletHttpContext) server.getContext("/");
        context.addServlet("/MO", "jetty.HelloWorldServlet");

        server.start();
        */

        } catch (Exception ex) {
            Logger.getLogger(Jetty.class.getName()).log(Level.SEVERE, null, ex);
        }

    }
} 

Servlet类:

package jetty;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HelloWorldServlet extends HttpServlet
{
    @Override
    protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException
    {
        String appid = httpServletRequest.getParameter("appid");
        String conta = httpServletRequest.getParameter("conta");

        System.out.println("Appid : "+appid);
        System.out.println("Conta : "+conta);

        httpServletResponse.setContentType("text/plain");
        PrintWriter out = httpServletResponse.getWriter();
        out.println("Hello World!");
        out.close();
    }
}

2
这个问题要求一个纯粹的Java SE解决方案。您会发现jetty实现了Java EE API。
Sridhar '09

Jetty使用标准Java SE可以完美运行,因此符合要求。它实现了Java EE API的某些部分,不需要它。它们是有区别的。
David Tonhofer 2013年

1
这不符合条件。“仅使用Java SE API”*.Servlet.jar并且*.jetty.jar显然不是Java SE的一部分。
icza 2014年

我需要设置码头吗?或者我可以解开这两个罐子并运行该文件?
Paul Preibisch 2015年


4

上面所有的答案都有关单主线程请求处理程序的详细信息。

设置:

 server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());

允许使用执行程序服务通过多个线程提供多个请求。

因此,最终代码将如下所示:

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class App {
    public static void main(String[] args) throws Exception {
        HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
        server.createContext("/test", new MyHandler());
        //Thread control is given to executor service.
        server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
        server.start();
    }
    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            String response = "This is the response";
            long threadId = Thread.currentThread().getId();
            System.out.println("I am thread " + threadId );
            response = response + "Thread Id = "+threadId;
            t.sendResponseHeaders(200, response.length());
            OutputStream os = t.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }
}

3

结帐简单。它是一个非常简单的嵌入式服务器,内置了对多种操作的支持。我特别喜欢它的线程模型。

惊人!



2

Apache Commons HttpCore项目如何?

来自网站:... HttpCore目标

  • 最基本的HTTP传输方面的实现
  • 在良好的性能和API的清晰度和表达能力之间取得平衡
  • 小(可预测)的内存占用
  • 自包含的库(JRE之外没有外部依赖项)

那可能太低级了。除非一个人想自己处理所有概念,例如分块,编码等,否则至少应该针对一种在Servlet API级别上调用代码的解决方案。虽然这可能很有趣。
David Tonhofer

2

试试这个https://github.com/devashish234073/Java-Socket-Http-Server/blob/master/README.md

该API使用套接字创建了一个HTTP服务器。

  1. 它以文本形式从浏览器获取请求
  2. 解析它以检索URL信息,方法,属性等。
  3. 使用定义的URL映射创建动态响应
  4. 将响应发送到浏览器。

例如,这是Response.java类中的构造函数将原始响应转换为http响应的方式:

public Response(String resp){
    Date date = new Date();
    String start = "HTTP/1.1 200 OK\r\n";
    String header = "Date: "+date.toString()+"\r\n";
    header+= "Content-Type: text/html\r\n";
    header+= "Content-length: "+resp.length()+"\r\n";
    header+="\r\n";
    this.resp=start+header+resp;
}

1

您可以编写一个非常简单的嵌入式Jetty Java服务器。

嵌入式Jetty意味着服务器(Jetty)与应用程序一起提供,而不是在外部Jetty服务器上部署应用程序。

因此,如果以非嵌入式方式将您的Web应用程序内置到WAR文件中并部署到某个外部服务器(Tomcat / Jetty等)中,则在嵌入式Jetty中,您可以编写Webapp并在同一代码库中实例化Jetty服务器。

您可以git clone并使用嵌入式Jetty Java服务器的示例:https : //github.com/stas-slu/embedded-jetty-java-server-example

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.