Jetty 9.x ProxyServlet - 如何在 XML 中正确设置 ServletContext
Jetty 9.x ProxyServlet - how to set up ServletContext correctly in XML
旨在使用 webapp servlet 和代理 servlet 运行 以及部署和控制台日志记录等其他工具在本地启动 Jetty。所有 Jetty 配置都在 XML 文件中。
代理 servlet 会将前缀为 /media/*
的 GET
请求反向代理到外部站点 https://example-server/
。所以 http://localhost:8080/media/image.jpg will pass through to 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.xml
和 https://dzone.com/articles/configuring-jetty-servlet-proxy
根据 DZone 指南,我更新了 Jetty 9.x 的 class 名称。所以 org.eclipse.jetty.servlets.ProxyServlet
现在是 org.eclipse.jetty.proxy.ProxyServlet
并且 proxyTo
和 prefix
参数必须以小写 p
.
开头
已检查 jetty-proxy-9.4.12.v20180830.jar
作为库包含在 Jetty 的启动配置中。
对于日志记录,Jetty 命令行包括 -Dorg.eclipse.jetty.proxy.LEVEL=DEBUG
(我建议其他人对 ProxyServlet 进行故障排除。)
</code></h2>
<p><code>
问题:没有任何反应。 ProxyServlet
未在对“http://localhost:8080/media/image.jpg”的 GET
请求上激活。
这是显示 ServletContextHandler
开始的日志行。
2018-09-28 15:26:46.045:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1e028a9{"",null,AVAILABLE}
我想对此有一个简单的解决方案,比如正确设置 ServletContext,但我不知道如何在 XML 中做到这一点,非常感谢您的帮助。 Jettydocumentation这上面很薄
</code></h2>
<p><code>
现在,如果我将 jetty.xml
更改为下面的内容,那么代理 会 在 GET
对“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) to null/media
is because the ServletContext.getContextPath()
is null. And that causes a redirect to null
because of this source code。_prefix
设置为 null/media
,没有什么可以匹配的。可能这是一个错误,我已经打开了一个问题。
一个解决方案——不完全是我想做的,但它有效——是从与 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>
其他陷阱:
- 您
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
- Web 应用程序必须在 Jetty 版本更改时更新
web.xml
- 对于远程托管的应用程序来说可能是个问题
- 每个 webapp 都必须包含这个,而不是 "built in" 到 Jetty
- 与 Jetty 能够为不同的路径设置不同的 servlet 相比,它感觉不够优雅 - 这里是否存在性能问题,因为代理 URL 现在也被 webapp 的过滤器解析?
- 可能会在代理请求周期完成时阻塞 webapp 的线程(需要测试...)
这是使用 ${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
码头模块,这将代理 类 放在服务器类路径上。
然后启用deploy
jetty模块,在${jetty.base}/webapps/
目录下查找webapps的配置并部署。
最后,XML 可部署设置有一个 javax.servlet.ServletContext
,在 /
contextPath 和一个定义的 servlet,ProxyServlet$Transparent
带有一些初始参数.
旨在使用 webapp servlet 和代理 servlet 运行 以及部署和控制台日志记录等其他工具在本地启动 Jetty。所有 Jetty 配置都在 XML 文件中。
代理 servlet 会将前缀为 /media/*
的 GET
请求反向代理到外部站点 https://example-server/
。所以 http://localhost:8080/media/image.jpg will pass through to 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.xml
和 https://dzone.com/articles/configuring-jetty-servlet-proxy
根据 DZone 指南,我更新了 Jetty 9.x 的 class 名称。所以 org.eclipse.jetty.servlets.ProxyServlet
现在是 org.eclipse.jetty.proxy.ProxyServlet
并且 proxyTo
和 prefix
参数必须以小写 p
.
已检查 jetty-proxy-9.4.12.v20180830.jar
作为库包含在 Jetty 的启动配置中。
对于日志记录,Jetty 命令行包括 -Dorg.eclipse.jetty.proxy.LEVEL=DEBUG
(我建议其他人对 ProxyServlet 进行故障排除。)
</code></h2>
<p><code>
问题:没有任何反应。 ProxyServlet
未在对“http://localhost:8080/media/image.jpg”的 GET
请求上激活。
这是显示 ServletContextHandler
开始的日志行。
2018-09-28 15:26:46.045:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler@1e028a9{"",null,AVAILABLE}
我想对此有一个简单的解决方案,比如正确设置 ServletContext,但我不知道如何在 XML 中做到这一点,非常感谢您的帮助。 Jettydocumentation这上面很薄
</code></h2>
<p><code>
现在,如果我将 jetty.xml
更改为下面的内容,那么代理 会 在 GET
对“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>
<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) to null/media
is because the ServletContext.getContextPath()
is null. And that causes a redirect to null
because of this source code。_prefix
设置为 null/media
,没有什么可以匹配的。可能这是一个错误,我已经打开了一个问题。
一个解决方案——不完全是我想做的,但它有效——是从与 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>
其他陷阱:
- 您
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
- Web 应用程序必须在 Jetty 版本更改时更新
web.xml
- 对于远程托管的应用程序来说可能是个问题 - 每个 webapp 都必须包含这个,而不是 "built in" 到 Jetty
- 与 Jetty 能够为不同的路径设置不同的 servlet 相比,它感觉不够优雅 - 这里是否存在性能问题,因为代理 URL 现在也被 webapp 的过滤器解析?
- 可能会在代理请求周期完成时阻塞 webapp 的线程(需要测试...)
这是使用 ${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
码头模块,这将代理 类 放在服务器类路径上。
然后启用deploy
jetty模块,在${jetty.base}/webapps/
目录下查找webapps的配置并部署。
最后,XML 可部署设置有一个 javax.servlet.ServletContext
,在 /
contextPath 和一个定义的 servlet,ProxyServlet$Transparent
带有一些初始参数.