如何从内部服务器在 Java 网络应用程序中提供静态内容?
How to serve static content in a Java web app from internal server?
这是一个标准(可能微不足道)的情况,但我找不到关于该主题的详细信息。
假设我们有一个 Web 应用程序 A (http://my-webapp
) 和一个文件服务器 F (http://file-server
).
为清楚起见:
- A 在 Jetty 9 上 运行;
- F 对 Jetty 服务器可见,对客户端不可见。
在 A 中显示存储在 F 上的图片的最佳做法是什么?
假设客户端发出请求 http://my-webapp/pictures/123
,其中 123
- 任何 id,以某种方式指向存储为 http://file-server/storage/xxx123.jpg
的图片,并希望在浏览器中看到该图片。
"Best practice" 占地地段。
出于负载和性能方面的原因,最好使用 Web 服务器(如 NGINX 或 Apache)而不是应用程序服务器来为静态资产提供服务。大多数生产环境都有这样的设置,必要时使用 Web 服务器将请求代理到应用程序服务器。
如果您有这样的设置,您可以将 F 上的图像驱动器映射为网络服务器上的驱动器,并使用 .htaccess 重写规则来处理文件名逻辑。
如果因为无法在正则表达式或类似表达式中捕获文件名逻辑而无法做到这一点,您可以在 A 上编写一个 servlet 以发出重定向到 "regular" 网址。大致如下:
- 客户请求
http://my-webapp/pictures/123
- servlet 将 /pictures/123 翻译成 http://my-webapp/static_pictures/xxx123
- servlet 发出 302 重定向到 http://my-webapp/static_pictures/xxx123
- 客户端遵循重定向
我强烈建议您 不要 使用 servlet 从 F 读取文件,然后将其流式传输到浏览器;这会消耗您的应用程序服务器上的大量内存,并且可能会减慢速度甚至失败,具体取决于您的本地网络状况。您的应用程序的性能几乎肯定会在负载下迅速恶化。
我建议将以下解决方案作为一个最小示例,它可能是一个很好的起点。
.htaccess
的重定向似乎在底层做了类似的事情。
其实这个问题应该是在没有外部工具(比如Apache httpd或Nginx)介入的情况下由web应用服务器自己解决的。
1。在 web.xml
中声明 servlet
<servlet>
<servlet-name>pictures</servlet-name>
<servlet-class>myapplication.servlets.HiddenFileServlet </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pictures</servlet-name>
<url-pattern>/pictures/*</url-pattern>
</servlet-mapping>
2。实施 servlet
public class HiddenFileServlet extends HttpServlet
{
@Inject
MyService myService; // a service for paths finding on http://file-server
@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws IOException
{
String requestedUri = req.getRequestURI();
String fileName = myService.getFileName( requestedUri );
String mime = getServletContext().getMimeType( fileName );
if ( mime == null )
{
resp.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
return;
}
else
{
resp.setContentType( mime );
}
// path on http://file-server/storage
URL fileFullPath = myService.getInternalPath( requestedUri );
URL file = new URL( fileFullPath );
try (
InputStream in = file.openStream();
OutputStream out = resp.getOutputStream()
)
{
org.apache.commons.compress.utils.IOUtils.copy( in, out );
}
}
}
这是一个标准(可能微不足道)的情况,但我找不到关于该主题的详细信息。
假设我们有一个 Web 应用程序 A (http://my-webapp
) 和一个文件服务器 F (http://file-server
).
为清楚起见:
- A 在 Jetty 9 上 运行;
- F 对 Jetty 服务器可见,对客户端不可见。
在 A 中显示存储在 F 上的图片的最佳做法是什么?
假设客户端发出请求 http://my-webapp/pictures/123
,其中 123
- 任何 id,以某种方式指向存储为 http://file-server/storage/xxx123.jpg
的图片,并希望在浏览器中看到该图片。
"Best practice" 占地地段。
出于负载和性能方面的原因,最好使用 Web 服务器(如 NGINX 或 Apache)而不是应用程序服务器来为静态资产提供服务。大多数生产环境都有这样的设置,必要时使用 Web 服务器将请求代理到应用程序服务器。
如果您有这样的设置,您可以将 F 上的图像驱动器映射为网络服务器上的驱动器,并使用 .htaccess 重写规则来处理文件名逻辑。
如果因为无法在正则表达式或类似表达式中捕获文件名逻辑而无法做到这一点,您可以在 A 上编写一个 servlet 以发出重定向到 "regular" 网址。大致如下:
- 客户请求
http://my-webapp/pictures/123
- servlet 将 /pictures/123 翻译成 http://my-webapp/static_pictures/xxx123
- servlet 发出 302 重定向到 http://my-webapp/static_pictures/xxx123
- 客户端遵循重定向
我强烈建议您 不要 使用 servlet 从 F 读取文件,然后将其流式传输到浏览器;这会消耗您的应用程序服务器上的大量内存,并且可能会减慢速度甚至失败,具体取决于您的本地网络状况。您的应用程序的性能几乎肯定会在负载下迅速恶化。
我建议将以下解决方案作为一个最小示例,它可能是一个很好的起点。
.htaccess
的重定向似乎在底层做了类似的事情。
其实这个问题应该是在没有外部工具(比如Apache httpd或Nginx)介入的情况下由web应用服务器自己解决的。
1。在 web.xml
中声明 servlet<servlet>
<servlet-name>pictures</servlet-name>
<servlet-class>myapplication.servlets.HiddenFileServlet </servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pictures</servlet-name>
<url-pattern>/pictures/*</url-pattern>
</servlet-mapping>
2。实施 servlet
public class HiddenFileServlet extends HttpServlet
{
@Inject
MyService myService; // a service for paths finding on http://file-server
@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp ) throws IOException
{
String requestedUri = req.getRequestURI();
String fileName = myService.getFileName( requestedUri );
String mime = getServletContext().getMimeType( fileName );
if ( mime == null )
{
resp.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
return;
}
else
{
resp.setContentType( mime );
}
// path on http://file-server/storage
URL fileFullPath = myService.getInternalPath( requestedUri );
URL file = new URL( fileFullPath );
try (
InputStream in = file.openStream();
OutputStream out = resp.getOutputStream()
)
{
org.apache.commons.compress.utils.IOUtils.copy( in, out );
}
}
}