374

Is there a way to create a very basic HTTP server (supporting only GET/POST) in Java using just the Java SE API, without writing code to manually parse HTTP requests and manually format HTTP responses? The Java SE API nicely encapsulates the HTTP client functionality in HttpURLConnection, but is there an analog for HTTP server functionality?

Just to be clear, the problem I have with a lot of ServerSocket examples I've seen online is that they do their own request parsing/response formatting and error handling, which is tedious, error-prone, and not likely to be comprehensive, and I'm trying to avoid it for those reasons.

4

19 回答 19

531

从 Java SE 6 开始, Sun Oracle JRE中有一个内置的 HTTP 服务器。Java 9 模块名称是jdk.httpserver. com.sun.net.httpserver包摘要概述了所涉及的类并包含示例。

这是从他们的文档中复制粘贴的启动示例。您可以在 Java 6+ 上复制'n'粘贴'n'运行它。
(对于所有试图编辑它的人,因为它是一段丑陋的代码,请不要,这是复制粘贴,不是我的,而且你不应该编辑引用,除非它们在原始来源中发生了变化)

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()方法也必须显式指定您随后在响应标头中指定的字符集。唉,尽管对初学者有误导性,但这毕竟只是一个基本的启动示例。

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

这是回应


至于使用com.sun.*类,请注意,与某些开发人员的想法相反,众所周知的常见问题解答为什么开发人员不应该编写调用“sun”包的程序绝对不禁止这样做。该常见问题解答涉及供 Oracle JRE 内部使用的sun.*包(例如sun.misc.BASE64Encoder)(因此,当您在不同的 JRE 上运行应用程序时,它会杀死您的应用程序),而不是com.sun.*包。Sun/Oracle 也只是像 Apache 等其他公司一样,自己在 Java SE API 之上开发软件。此外,HttpServer每个 JDK 中都必须存在此特定内容,因此绝对不会出现像 package.json 那样的“可移植性”问题sun.*com.sun.*不鼓励使用类(但不是禁止) 当它涉及某个 Java API 的实现时,例如 GlassFish (Java EE impl)、Mojarra (JSF impl)、Jersey (JAX-RS impl) 等。

于 2010-09-17T02:34:14.920 回答
50

查看NanoHttpd

NanoHTTPD 是一个轻量级 HTTP 服务器,设计用于嵌入其他应用程序,在修改后的 BSD 许可证下发布。

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

于 2010-09-17T02:29:25.977 回答
30

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);
    }
}
于 2014-06-08T07:03:29.613 回答
30

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

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

虽然我可能认为像JettyApache Http ComponentsNetty等 HTTP 库更像是一个原始的 HTTP 处理工具。标签是非常主观的,并且取决于您被要求为小型站点提供的东西的种类。我根据问题的精神做出这种区分,特别是关于...的评论

  • “......无需编写代码来手动解析 HTTP 请求和手动格式化 HTTP 响应......”

这些原始工具可让您做到这一点(如其他答案中所述)。他们并不真正适合制作轻型、嵌入式或迷你服务器的现成风格。迷你服务器可以为您提供与全功能 Web 服务器(例如Tomcat)类似的功能,无需花哨、低容量、99% 的时间都具有良好的性能。瘦服务器似乎更接近原始措辞,只是比原始措辞多一点,可能具有有限的子集功能,足以让您在 90% 的时间看起来不错。我对 raw 的想法是让我在 75% 到 89% 的时间看起来都不错,而无需额外的设计和编码。我认为如果/当你达到 WAR 文件的级别时,我们已经为 bonsi 服务器留下了“小”,看起来就像大型服务器所做的一切都更小。

瘦服务器选项

迷你服务器选项:

  • Spark Java ... 很多帮助结构(如过滤器、模板等)都可以让好事成为可能。
  • MadVoc ...旨在成为盆景,很可能就是这样;-)

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

于 2014-09-04T15:05:18.877 回答
25

看看“Jetty”网络服务器Jetty。一款出色的开源软件,似乎可以满足您的所有要求。

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

于 2010-09-17T01:36:15.973 回答
20

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

  • 不是那么轻量级或简单的完整服务器(对于轻量级的极端定义。)
  • 真正的轻量级服务器,它不是 HTTP 服务器,而是美化的 ServerSocket 示例,它们甚至不符合远程 RFC 并且不支持通常需要的基本功能。

所以...我开始编写JLHTTP - The Java Lightweight HTTP Server

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

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

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

于 2016-02-25T21:51:25.260 回答
12

Spark 是最简单的,这里有一个快速入门指南:http ://sparkjava.com/

于 2015-04-02T12:52:06.010 回答
9

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

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

大多数非常轻量级的 httpserver 不提供对 servlet 的支持,但我们需要它们,所以我想我会分享。

下面的例子提供了基本的 servlet 支持,或者对于尚未实现的东西抛出和 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());
    }
}
于 2013-11-28T08:55:50.013 回答
9

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

环境:

 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();
        }
    }
}
于 2018-10-17T05:23:28.087 回答
7

您还可以查看一些 NIO 应用程序框架,例如:

  1. 网状:http : //jboss.org/netty
  2. Apache Mina:http ://mina.apache.org/ 或其子项目 AsyncWeb:http ://mina.apache.org/asyncweb/
于 2010-09-18T12:04:57.060 回答
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);
        }

    }
} 

小服务程序类:

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();
    }
}
于 2012-09-16T11:36:45.620 回答
6

我强烈建议您研究Simple,特别是如果您不需要 Servlet 功能而只需访问请求/响应对象。如果您需要 REST,您可以将 Jersey 放在上面,如果您需要输出 HTML 或类似内容,则可以使用 Freemarker。我真的很喜欢你可以用这个组合做些什么,而且要学习的 API 相对较少。

于 2010-09-17T18:29:40.287 回答
3

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

惊人!

于 2015-07-15T10:43:57.327 回答
3

试试这个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;
}
于 2018-05-11T07:01:17.860 回答
3

退房takes。查看https://github.com/yegor256/takes以获取快速信息

于 2015-10-15T14:20:38.713 回答
2

Apache Commons HttpCore项目怎么样?

来自网站:... HttpCore 目标

  • 最基本的 HTTP 传输方面的实现
  • 在良好的性能与 API 的清晰性和表现力之间取得平衡
  • 小(可预测的)内存占用
  • 自包含库(除 JRE 之外没有外部依赖项)
于 2013-02-11T21:52:42.017 回答
1

TCP 套接字级别的一个非常基本的 HTTP 服务器的示例:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class NaiveHttpServer {

  public static void main(String[] args) throws IOException {
    String hostname = InetAddress.getLocalHost().getHostName();
    ServerSocket serverSocket = new ServerSocket(8089);
    while (true) {
      Socket clientSocket = serverSocket.accept();
      PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
      BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
      String s = in.readLine();
      System.out.println(s);
      while ("\r\n".equals(in.readLine())); 
      if ("GET /hostname HTTP/1.1".equals(s)) {
        out.println("HTTP/1.1 200 OK");
        out.println("Connection: close");
        out.println("Content-Type: text/plain");
        out.println("Content-Length:" + hostname.length());
        out.println();
        out.println(hostname);
      } else {
        out.println("HTTP/1.1 404 Not Found");
        out.println("Connection: close");
        out.println();    
      }
      out.flush();
    }
  }
}

该示例提供计算机的主机名。

于 2021-11-04T14:52:03.420 回答
1

自 Java 11 以来,旧com.sun.net.httpserver的 API 再次成为公共且被接受的 API。您可以将其作为HttpServer类获取,作为jdk.httpserver模块的一部分提供。请参阅https://docs.oracle.com/en/java/javase/11/docs/api/jdk.httpserver/com/sun/net/httpserver/HttpServer.html

这个类实现了一个简单的 HTTP 服务器。HttpServer 绑定到 IP 地址和端口号,并侦听来自该地址上的客户端的传入 TCP 连接。子类 HttpsServer 实现了一个处理 HTTPS 请求的服务器。

因此,除了它的局限性之外,没有理由再避免使用它。

我用它在服务器应用程序中发布控制接口。从客户端请求读取User-agent标头我什text/plain至响应 CLI 工具,curl或者以更优雅的 HTML 方式响应任何其他浏览器。

很酷很容易。

于 2021-08-20T22:51:17.457 回答
1

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

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

因此,如果在非嵌入式方法中,您的 webapp 内置到部署到某个外部服务器(Tomcat / Jetty / 等)的 WAR 文件中,则在嵌入式 Jetty 中,您编写 webapp 并在相同的代码库中实例化 jetty 服务器。

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

于 2017-06-29T11:14:44.727 回答