首页 文章

Jetty 9.x ProxyServlet - 如何在XML中正确设置ServletContext

提问于
浏览
0

旨在通过运行webapp servlet和代理servlet以及部署和控制台日志记录等其他工具在本地启动Jetty . 所有Jetty配置都在XML文件中 .

代理servlet将 GET 请求前缀 /media/* 反向代理到外部站点 https://example-server/ . 所以http://localhost:8080/media/image.jpg将通过https://media-server/image.jpg .

这是我的 jetty.xml 的摘录:

<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="context" class="org.eclipse.jetty.servlet.ServletContextHandler">
           <Arg><Get class="org.eclipse.jetty.servlet.ServletContextHandler" name="SESSIONS"/></Arg>
           <Call name="setContextPath" arg="/"/>
           <Set name="servletHandler">
             <New id="handler" class="org.eclipse.jetty.servlet.ServletHandler">
               <Call id="holder" name="addServletWithMapping" arg="org.eclipse.jetty.proxy.ProxyServlet$Transparent,/media/*">
                 <Call name="setInitParameter" arg="proxyTo,https://media-server"/>
                 <Call name="setInitParameter" arg="prefix,/media"/>
               </Call>
             </New>
           </Set>
         </New>
       </Item>
       <Item>
         <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
       </Item>
     </Array>
    </Set>
  </New>
</Set>

上面的XML应该等同于这个Java代码 .

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
ServletHandler handler = new ServletHandler();
ServletHolder holder = handler.addServletWithMapping(ProxyServlet$Transparent.class, "/media/*");
holder.setInitParameter("proxyTo", "https://media-server");
holder.setInitParameter("prefix", "/media");
context.setServletHandler(handler);

这是根据默认 jetty.xmlhttps://dzone.com/articles/configuring-jetty-servlet-proxy改编的

从DZone指南我更新了Jetty 9.x的类名 . 所以 org.eclipse.jetty.servlets.ProxyServlet 现在是 org.eclipse.jetty.proxy.ProxyServletproxyToprefix 参数必须以小写 p 开头 .

检查 jetty-proxy-9.4.12.v20180830.jar 是否包含在Jetty启动配置中的库中 .

对于日志记录,Jetty命令行包括 -Dorg.eclipse.jetty.proxy.LEVEL=DEBUG (我建议其他人对ProxyServlet进行故障排除 . )

`` The problem: 什么都没发生 . ProxyServlet 未激活 GET 对`http://localhost:8080/media/image.jpg'的请求 .

这是显示 ServletContextHandler 正在启动的日志行 .

2018-09-28 15:26:46.045:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1e028a9{"",null,AVAILABLE}

我想's simple solution to this, like setting the ServletContext correctly, but I can'知道如何用XML做到这一点,并且非常感谢一些帮助 . Jetty documentation对此很薄 .

`` 现在,如果我将 jetty.xml 更改为以下,则 GET 上的代理 does 激活请求“http://localhost:8080/media/image.jpg” .

<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="handler" class="org.eclipse.jetty.servlet.ServletHandler">
           <Call id="holder" name="addServletWithMapping" arg="org.eclipse.jetty.proxy.ProxyServlet$Transparent,/media/*">
             <Call name="setInitParameter" arg="proxyTo,https://media-server"/>
             <Call name="setInitParameter" arg="prefix,/media"/>
           </Call>
         </New>
       </Item>
       <Item>
         <New id="DefaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler"/>
       </Item>
     </Array>
    </Set>
  </New>
</Set>

日志显示ProxyServlet激活如下:

2018-09-28 14:22:14.904:DBUG:oejpP.194a1b5:qtp22374712-13: org.eclipse.jetty.proxy.ProxyServlet$Transparent-194a1b5 @ null/media to https://media-server
2018-09-28 14:22:14.904:DBUG:oejpP.194a1b5:qtp22374712-13: 21964987 rewriting: http://localhost:8080/media/image.jpg -> null

但是这里代理失败了,因为它有一个 null 上下文 . 因此,前缀已设置(source code)为 null/media ,因为 ServletContext.getContextPath() 为空 . 由于this source code,这会导致重定向到 null . 将 _prefix 设置为 null/media ,没有's going to match that. Possibly that'是一个错误,我已经打开了一个问题 .

2 回答

  • 1

    以下是使用 ${jetty.base} 目录中的 ProxyServlet 的示例 .

    $ mkdir proxy-example-base
    $ cd proxy-example-base/
    $ java -jar ../../jetty-home-9.4.12.v20180830/start.jar --add-to-start=http,deploy,proxy
    INFO  : webapp          transitively enabled, ini template available with --add-to-start=webapp
    INFO  : server          transitively enabled, ini template available with --add-to-start=server
    INFO  : proxy           initialized in ${jetty.base}/start.ini
    INFO  : security        transitively enabled
    INFO  : servlet         transitively enabled
    INFO  : http            initialized in ${jetty.base}/start.ini
    INFO  : client          transitively enabled
    INFO  : threadpool      transitively enabled, ini template available with --add-to-start=threadpool
    INFO  : deploy          initialized in ${jetty.base}/start.ini
    MKDIR : ${jetty.base}/webapps
    INFO  : Base directory was modified
    $ ls -la
    total 8
    drwxr-xr-x   4 joakim  staff   136 Oct  1 14:10 ./
    drwxr-xr-x  17 joakim  staff   578 Oct  1 14:10 ../
    -rw-r--r--   1 joakim  staff  2146 Oct  1 14:10 start.ini
    drwxr-xr-x   3 joakim  staff   102 Oct  1 14:11 webapps/
    $ cp ~/Downloads/media-proxy.xml webapps/
    $ cat webapps/media-proxy.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
    <Configure class="org.eclipse.jetty.servlet.ServletContextHandler">
      <Set name="contextPath">/</Set>
      <Call name="addServlet">
        <Arg>org.eclipse.jetty.proxy.ProxyServlet$Transparent.class</Arg>
        <Arg>/media/*</Arg>
        <Set name="InitOrder">1</Set>
        <Call name="setInitParameter">
          <Arg>proxyTo</Arg>
          <Arg>https://media-server/</Arg>
        </Call>
        <Call name="setInitParameter">
          <Arg>prefix</Arg>
          <Arg>/media</Arg>
        </Call>
      </Call>
    </Configure>
    

    这种方式的工作方式是 ${jetty.base} 配置为启用 proxy jetty模块,这将代理类放在服务器类路径上 .

    然后启用 deploy jetty模块以查找 ${jetty.base}/webapps/ 目录中的webapps配置并进行部署 .

    最后,XML可部署设置为在 / contextPath处具有 javax.servlet.ServletContext ,并且具有一个定义的servlet, ProxyServlet$Transparent 具有一些init参数 .

  • 1

    一个解决方案 - 不完全是我想做的,但它的工作原理 - 是从与webapp相关联的 web.xml 启动ProxyServlet .

    <servlet>
      <servlet-name>JettyProxy</servlet-name>
      <servlet-class>org.eclipse.jetty.proxy.ProxyServlet$Transparent</servlet-class>
      <init-param>
        <param-name>proxyTo</param-name>
        <param-value>https://media-server</param-value>
      </init-param>
      <init-param>
        <param-name>prefix</param-name>
        <param-value>/media</param-value>
      </init-param>
      <load-on-startup>1</load-on-startup>
      <async-supported>true</async-supported>
    </servlet>
    <servlet-mapping>
      <servlet-name>JettyProxy</servlet-name>
      <url-pattern>/media/*</url-pattern>
    </servlet-mapping>
    

    Additional gotchas:

    • web.xml 中定义的任何过滤器现在也需要 <async-supported>true</async-supported>

    • 您的项目现在需要 jetty-proxy 库jar作为依赖项(版本必须与您的Jetty版本匹配),如下所示:

    <dependency>
       <groupId>org.eclipse.jetty</groupId>
      <artifactId>jetty-proxy</artifactId>
      <version>9.4.12.v20180830</version>
    </dependency>
    

    web.xml 这样做,以及从我想在OP中做的Jetty自己的配置中做到这一点有一些区别 .

    • 代理的URL现在必须采用此形式(其中webapp是webapp名称):http://localhost:8080/webapp/media/image.jpg
      _009_当Jetty版本发生变化时,webapp必须更新 web.xml - 远程托管应用可能会出现问题

    • 每个webapp必须包含这个,而不是它是Jetty的"built in"
      __9_与Jetty能够为不同的路径设置不同的servlet相比,感觉不够优雅 - 这里是否有性能影响,因为代理的URL现在也被webapp的过滤器解析了?

    • 可能在代理请求周期完成时阻止webapp的线程(需要测试...)

相关问题