如何通过 xml 配置在 SSL 模式下启用嵌入式 jetty 9?

How to enable embedded jetty 9 in SSL mode through xml configuration?

我使用了单个 jetty.xml 并在此处添加了我的上下文和 http 配置来处理我的请求。我遵循了这种方法,因为我之前使用的是旧的 jetty 6,然后升级到 9,他们在那里划分了文件,我对较新的 jetty 中提到的配置感到困惑。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">

<!-- =============================================================== -->
<!-- Documentation of this file format can be found at:              -->
<!-- https://www.eclipse.org/jetty/documentation/current/            -->
<!--                                                                 -->
<!-- Additional configuration files are available in $JETTY_HOME/etc -->
<!-- and can be mixed in. See start.ini file for the default         -->
<!-- configuration files.                                            -->
<!--                                                                 -->
<!-- For a description of the configuration mechanism, see the       -->
<!-- output of:                                                      -->
<!--   java -jar start.jar -?                                        -->
<!-- =============================================================== -->

<!-- =============================================================== -->
<!-- Configure a Jetty Server instance with an ID "Server"           -->
<!-- Other configuration files may also configure the "Server"       -->
<!-- ID, in which case they are adding configuration to the same     -->
<!-- instance.  If other configuration have a different ID, they     -->
<!-- will create and configure another instance of Jetty.            -->
<!-- Consult the javadoc of o.e.j.server.Server for all              -->
<!-- configuration that may be set here.                             -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">

    <New id="threadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
        <Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
        <Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
        <Set name="reservedThreads" type="int"><Property name="jetty.threadPool.reservedThreads" default="-1"/></Set>
        <Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
        <Set name="detailedDump" type="boolean"><Property name="jetty.threadPool.detailedDump" default="false"/></Set>
    </New>


    <!-- =========================================================== -->
    <!-- Add shared Scheduler instance                               -->
    <!-- =========================================================== -->
    <Call name="addBean">
        <Arg>
            <New class="org.eclipse.jetty.util.thread.ScheduledExecutorScheduler">
                <Arg name="name"><Property name="jetty.scheduler.name"/></Arg>
                <Arg name="daemon" type="boolean"><Property name="jetty.scheduler.daemon" default="false" /></Arg>
                <Arg name="threads" type="int"><Property name="jetty.scheduler.threads" default="-1" /></Arg>
            </New>
        </Arg>
    </Call>

    <Set name="handler">
        <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
            <Set name="handlers">
                <Array type="org.eclipse.jetty.server.Handler">
                    <Item>
                        <New id="Contexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
                    </Item>
<!--                    <Item>-->
<!--                        <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>-->
<!--                    </Item>-->
                    <Item>
                        <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"/>
                    </Item>
                </Array>
            </Set>
        </New>
    </Set>
    
    <!-- ======================================================= -->
    <!-- Configure a Context for CTS                              -->
    <!-- ======================================================= -->
    <New class="org.eclipse.jetty.servlet.ServletContextHandler">
        <Arg>
            <Ref id="Contexts"/>
        </Arg>
        <Arg>/cts</Arg>
        <Set name="resourceBase">
            <SystemProperty name="jetty.home" default="."/>/</Set>
        <Set name="sessionHandler">
            <New class="org.eclipse.jetty.server.session.SessionHandler"/>
        </Set>
        <Call name="addServlet">
            <Arg>com.documentum.cts.webservices.remote.TransformationServlet</Arg>
            <Arg>/</Arg>
        </Call>
    </New>
    <New class="org.eclipse.jetty.servlet.ServletContextHandler">
        <Arg>
            <Ref id="Contexts"/>
        </Arg>
        <Arg>/cts/resource</Arg>
        <Set name="resourceBase">
            <SystemProperty name="jetty.home" default="."/>/../resource/</Set>
        <Call name="addServlet">
            <Arg>com.documentum.cts.webservices.remote.FileProxyServlet</Arg>
            <Arg>/</Arg>
        </Call>
    </New>

    <!-- =========================================================== -->
    <!-- Http Configuration.                                         -->
    <!-- This is a common configuration instance used by all         -->
    <!-- connectors that can carry HTTP semantics (HTTP, HTTPS, etc.)-->
    <!-- It configures the non wire protocol aspects of the HTTP     -->
    <!-- semantic.                                                   -->
    <!--                                                             -->
    <!-- This configuration is only defined here and is used by      -->
    <!-- reference from other XML files such as jetty-http.xml,      -->
    <!-- jetty-https.xml and other configuration files which         -->
    <!-- instantiate the connectors.                                 -->
    <!--                                                             -->
    <!-- Consult the javadoc of o.e.j.server.HttpConfiguration       -->
    <!-- for all configuration that may be set here.                 -->
    <!-- =========================================================== -->

    <Call name="addConnector">
        <Arg>
            <New id="httpConnector" class="org.eclipse.jetty.server.ServerConnector">
                <Arg name="server">
                    <Ref refid="Server" />
                </Arg>
                <Set name="host">
                    <SystemProperty name="jetty.http.host"/>
                </Set>
                <Set name="port">
                    <Property name="jetty.http.port" deprecated="jetty.port" default="9096" />
                </Set>
                <Set name="idleTimeout">
                    <Property name="jetty.http.idleTimeout" deprecated="http.timeout" default="30000"/>
                </Set>
                <Get name="SelectorManager">
                    <Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
                </Get>
            </New>
        </Arg>
    </Call>


    <!-- =========================================================== -->
    <!-- Set the default handler structure for the Server            -->
    <!-- A handler collection is used to pass received requests to   -->
    <!-- both the ContextHandlerCollection, which selects the next   -->
    <!-- handler by context path and virtual host, and the           -->
    <!-- DefaultHandler, which handles any requests not handled by   -->
    <!-- the context handlers.                                       -->
    <!-- Other handlers may be added to the "Handlers" collection,   -->
    <!-- for example the jetty-requestlog.xml file adds the          -->
    <!-- RequestLogHandler after the default handler                 -->
    <!-- =========================================================== -->
    <Ref id="RequestLog">
        <Set name="requestLog">
            <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
                <Set name="filename">
                    <SystemProperty name="jetty.logs" default="../logs"/>/ws.request_yyyy_mm_dd.log</Set>
                <Set name="filenameDateFormat">yyyy_MM_dd</Set>
                <Set name="retainDays">90</Set>
                <Set name="append">true</Set>
                <Set name="extended">true</Set>
                <Set name="logCookies">false</Set>
                <Set name="LogTimeZone">GMT</Set>
            </New>
        </Set>
    </Ref>

    <!-- =========================================================== -->
    <!-- extra server options                                        -->
    <!-- =========================================================== -->
    <Set name="stopAtShutdown"><Property name="jetty.server.stopAtShutdown" default="true"/></Set>
    <Set name="stopTimeout"><Property name="jetty.server.stopTimeout" default="5000"/></Set>
    <Set name="dumpAfterStart"><Property name="jetty.server.dumpAfterStart" deprecated="jetty.dump.start" default="false"/></Set>
    <Set name="dumpBeforeStop"><Property name="jetty.server.dumpBeforeStop" deprecated="jetty.dump.stop" default="false"/></Set>

</Configure>

已编写以下代码来调用此配置:

Server myServer;
File theConfigFile = new File( "C://jetty//etc//jetty.xml" );
XmlConfiguration theXmlConfiguration = new XmlConfiguration( theConfigFile.toURL() );
theXmlConfiguration.configure( myServer );
myServer.start();

我想坚持使用 xml 配置 jetty 的方法,并在 SSL 模式下启用 http。有可能实现这一目标吗?提供的任何帮助都将非常有用。

天哪,这里有很多话要说。

在 Whosebug 上将大量不同的问题集中到一个问题中可不是个好主意!

  1. 正确使用<Ref>。是 <Ref refid="otherid">,不是 <Ref id="idtothisref">
  2. 不要使用 ServletContextHandlerWebAppContext 中的构造函数引用来绑定处理程序树中的位置或定义上下文路径。这些应该在 XML 中定义为在您想要它们的处理程序树的位置内。
  3. 不要重新定义 Scheduler,按照你现在的方式,你将有 2 个调度程序!
  4. 不要删除 DefaultHandler 是 Jetty 的关键组件,如果删除它,很多东西都会损坏。
  5. 不要在 Jetty 9 上使用 RequestLogHandler,它在 Jetty 8 中已被弃用,仅存在于 Jetty 9 中以防止破坏配置(你实际上没有一个功能齐全的 RequestLog 使用处理程序方法,使用服务器方法。
  6. NCSARequestLog 也已弃用,不要使用它,请使用 CustomRequestLog 并指定特定的 RequestLog.Writer
  7. 您的 ServletContextHandler 定义声明了一个 resourceBase,但随后在 / 的默认 servlet url 模式上添加了一个 servlet。这是一种相互矛盾的行为组合。
    • 您在 / 的默认 servlet url 模式(根据规范也称为“默认”)上有一个 resourceBase 和一个 DefaultServlet
    • 或者你有一个自定义的 servlet,它实现了 DefaultServlet 的所有必需功能,这样你就有了一个理智的 ServletContext(这意味着很多,包括错误处理、错误调度、http 缓存响应、缺少资源、非路径资源请求、完整的 http 规范路径规范化规则等。这只是 DefaultServlet 为您提供的表面内容以及一长串其他 ServletContext 规范定义的必需功能)
  8. /cts/resource 的上下文路径无效,无法使用。这种模式最好在现有上下文中使用 url-pattern 来完成。
    • 上下文路径规则是:
      • 必须以“/”开头。
      • 不能包含另一个斜杠“/”或“”
      • 必须符合URL路径编码规则。

您对 XmlConfiguration class 的使用未使用属性功能,或 XmlConfiguration class 中内置的 ID 映射,因此这意味着您在 XML 中对 <Property><SystemProperty> 以及 id="foo" 引用的所有用法均未扩展或有效。

要么正确使用 XmlConfiguration,要么删除 XML.

中的所有 <Property><SystemProperty> 元素

这是什么意思...

<!-- in your XML -->
<Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>

<!-- should be -->
<Set name="maxThreads" type="int">200</Set>

但为什么要为了避免正确使用 XmlConfiguration 而走极端呢?

使用没有属性的 XmlConfiguration 与直接使用 embedded-jetty 没有什么不同,所以跳过 XML 直接使用 embedded-jetty(更简单)。

如果您想正确使用 XmlConfiguration,请继续阅读。

首先,不要重做 Jetty 中已经存在的东西,使用它。这意味着采用现有的 XML、现有的默认属性,并正确使用 XmlConfiguration

在你的例子中 XML 唯一的“自定义”是你的 2 ServletContextHandlers,它们可以很容易地成为他们自己的 XML 文件。

首先,让我们向您展示如何使用直接使用 jetty-home 和 jetty-base 来完成这 2 个自定义 XML,后者使用 XML 和带有 XmlConfiguration 的属性。

我假设您在某处的 JAR 中有 class 用于 com.documentum.cts.webservices.remote.TransformationServletcom.documentum.cts.webservices.remote.FileProxyServlet 的文件(对于此演示,我们将其称为 app.jar)。

所以跟着...

$ curl -O https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-home/9.4.44.v20210927/jetty-home-9.4.44.v20210927.tar.gz
$ tar -zxf jetty-home-9.4.44.v20210927.tar.gz
$ mkdir my-jetty-base
[my-jetty-base]$ java -jar ../jetty-home-9.4.44.v20210927/start.jar --add-to-start=http,https,deploy,ext
[my-jetty-base]$ cp $HOME/projects/documentum/context.xml webapps/
[my-jetty-base]$ cp $HOME/projects/documentum/target/app.jar lib/ext
[my-jetty-base]$ mkdir webapps/context
[my-jetty-base]$ mkdir ctx-file-resources
[my-jetty-base]$ tree -F
.
├── ctx-file-resources/
├── etc/
│   └── keystore
├── lib/
│   └── ext/
│       └── app.jar
├── start.ini
└── webapps/
    └── context.xml

5 directories, 4 files
[my-jetty-base]$ cat webapps/context.xml
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">

<Configure id="custom-context" class="org.eclipse.jetty.servlet.ServletContextHandler">
  <Set name="contextPath">/ctx</Set>
  <Set name="resourceBase"><Property name="jetty.webapps"/>/context</Set>
  <Call name="addServlet">
    <Arg>com.custom.TranServlet</Arg>
    <Arg>/*</Arg>
  </Call>
  <Call id="fileProxHolder" name="addServlet">
    <Arg>com.custom.FileProxServlet</Arg>
    <Arg>/resource/*</Arg>
    <Call name="setInitParameter">
      <Arg>resourcesPath</Arg>
      <Arg><Property name="jetty.base"/>/ctx-file-resources</Arg>
    </Call>
  </Call>
</Configure>

现在如果我们启动这个服务器...

[]$ cd my-jetty-base
[my-jetty-base]$ java -jar ../jetty-home-9.4.44.v20210927/start.jar
2021-10-29 11:16:11.446:INFO::main: Logging initialized @407ms to org.eclipse.jetty.util.log.StdErrLog
2021-10-29 11:16:11.696:INFO:oejs.Server:main: jetty-9.4.44.v20210927; built: 2021-09-27T23:02:44.612Z; git: 8da83308eeca865e495e53ef315a249d63ba9332; jvm 11.0.12+7
2021-10-29 11:16:11.712:INFO:oejdp.ScanningAppProvider:main: Deployment monitor [file:///home/joakim/code/jetty/distros/bases/my-jetty-base/webapps/] at interval 1
2021-10-29 11:16:11.748:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1500b2f3{/ctx,file:///home/joakim/code/jetty/distros/bases/my-jetty-base/webapps/context,AVAILABLE}
2021-10-29 11:16:11.767:INFO:oejs.AbstractConnector:main: Started ServerConnector@12ec64c4{HTTP/1.1, (http/1.1)}{0.0.0.0:8080}
2021-10-29 11:16:11.796:INFO:oejus.SslContextFactory:main: x509=X509@4f704591(jetty,h=[jetty.eclipse.org],a=[],w=[]) for Server@3ddc6915[provider=null,keyStore=file:///home/joakim/code/jetty/distros/bases/my-jetty-base/etc/keystore,trustStore=file:///home/joakim/code/jetty/distros/bases/my-jetty-base/etc/keystore]
2021-10-29 11:16:11.796:INFO:oejus.SslContextFactory:main: x509=X509@704deff2(mykey,h=[jetty server],a=[],w=[]) for Server@3ddc6915[provider=null,keyStore=file:///home/joakim/code/jetty/distros/bases/my-jetty-base/etc/keystore,trustStore=file:///home/joakim/code/jetty/distros/bases/my-jetty-base/etc/keystore]
2021-10-29 11:16:11.872:INFO:oejs.AbstractConnector:main: Started ServerConnector@435f001f{SSL, (ssl, http/1.1)}{0.0.0.0:8443}
2021-10-29 11:16:11.873:INFO:oejs.Server:main: Started @834ms

好了,您已经具备了 ServletContextHandler 运行 所需的最低限度。 它可以仅在 1 个上下文中提供 http://localhost:8080/ctx/http://localhost:8080/ctx/resource/。 同时支持http和https。 没有webapp,没有war,等等

但如果您仍想完全在 XML 中自己完成此操作,请正确使用 XmlConfiguration

Eclipse Jetty Embedded Cookbook

中有一个这样的例子

参见:XmlServer,注意 这链接到 jetty-9.4.x 分支版本,在它们自己的分支上也有 jetty-10.0.xjetty-11.0.x 版本。

重要说明:Jetty 9.4.x 处于维护模式并且正在逐渐关闭,只有错误修复和安全补丁会进入该主要版本。
Eclipse Jetty 上的主线稳定分支是当前的 Jetty 10.0.x 和 11.0.x,将它们用于新开发。

要正确使用 XmlConfiguration,您必须是单独的 XML、属性和 ID 映射的war。

XmlConfiguration的正常执行循环如下...

/**
 * Configure for the list of XML Resources and Properties.
 *
 * @param xmls the xml resources (in order of execution)
 * @param properties the properties to use with the XML
 * @return the ID Map of configured objects (key is the id name in the XML, and the value is configured object)
 * @throws Exception if unable to create objects or read XML
 */
public static Map<String, Object> configure(List<Resource> xmls, Map<String, String> properties) throws Exception
{
    Map<String, Object> idMap = new HashMap<>();

    // Configure everything
    for (Resource xmlResource : xmls)
    {
        XmlConfiguration configuration = new XmlConfiguration(xmlResource);
        configuration.getIdMap().putAll(idMap);
        configuration.getProperties().putAll(properties);
        configuration.configure();
        idMap.putAll(configuration.getIdMap());
    }

    return idMap;
}

这需要一个 XML 的列表(按照正确的执行顺序)和一个属性映射。 XML 按顺序加载,您会返回 <id-string><configured-object> 的映射。

上面链接的示例有一个完整的示例,XML 来自 jetty-home(未修改),一些自定义 XML 包含新功能。 它甚至包括 SSL / HTTPS 层并展示了如何配置它(通过属性)。 它显示了如何设置 XML 列表和属性。 以及如何从 ID 映射中获取服务器。

为了获得最佳成功,请将 jetty-home 中的 XML 视为只读,不要修改它,不要编辑它,你不需要。 老实说,不要更改 XML,您不必这样做。在 Jetty 9.4 的 200 多万次安装中,没有一个经过验证的案例 需要从 jetty-home change/edit XML(人们认为他们需要,但这只是因为他们不明白如何 正确使用 Jetty XML 或 XmlConfiguration,并且将每个示例提供给我们作为他们需要编辑 XML 的“证明” 在您不需要的地方经常以多种方式显示)。 我们非常相信这一点,jetty-home 中的 XML 现在是只读的!