これはおそらくバグではなく、サーブレット仕様の制限です。JAX-RS の@ApplicationPath
処理方法の詳細は実装に固有であり、すべての実装について話すことはできませんが、典型的なアプローチは単にサーブレット URL パターンとして使用することだと思います。ジャージーの ServletContainerInitializer 実装を一例として見てみると、addServletWithApplication()
メソッドがサーブレットの作成とリクエストを処理するためのマッピングを担当していることがわかります。実際に、ジャージー サーブレット@ApplicationPath
コンテナーのマップとしてのパスを使用していることがわかります。道。
残念なことに、太古の昔から、サーブレットの仕様では、サーブレットを URL パスにマッピングする方法はほんの一握りしか許可されていませんでした。仕様のセクション 12.2 に記載されている Servlet 3.0 の現在のオプション-- 残念ながら PDF としてのみ利用可能であり、セクションごとにリンクすることはできません -- は次のとおりです。
/.../*
ここで、イニシャル/...
は 0 個以上のパス要素です
*.<ext>
<ext>
一致する拡張子はどこですか
- 空のパス/コンテキスト ルートにのみマップされる空の文字列
/
、単一のスラッシュ。コンテキスト内の「デフォルト」サーブレットを示し、他のものと一致しないものをすべて処理します
- 一致するリテラル値として扱われるその他の文字列
仕様の同じセクションには、一致するルールが適用される順序に関する特定のルールもありますが、短いバージョンは次のとおりです。リソース クラスがコンテキスト ルートでリクエストに応答するようにするには、パスとして/
またはを使用する必要があります。/*
を使用する/
と、コンテナのデフォルト サーブレットが置き換えられます。これは通常、静的リソースの処理を担当します。を使用する/*
と、貪欲になりすぎて、常にすべてに一致する必要があり、デフォルトのサーブレットが呼び出されることはありません。
したがって、サーブレットの URL パターンの制限によって決まるボックス内にいることを受け入れると、オプションはかなり制限されます。ここに私が考えることができるものがあります:
1) を使用@ApplicationPath("/")
し、静的リソースを名前または拡張子でコンテナのデフォルト サーブレット (Tomcat と Jetty では「デフォルト」という名前で、他については不明) に明示的にマップします。web.xml では、次のようになります。
<!-- All html files at any path -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<!-- Specifically index.html at the root -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
またはServletContextInitializerのように
public class MyInitializer implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) {
ctx.getServletRegistration("default").addMapping("*.html");
ctx.getServletRegistration("default").addMapping("/index.html");
}
}
マッチング ルールの記述方法により、拡張パターンがデフォルトのサーブレットに優先するため、静的ファイル拡張子ごとにマッピングを追加するだけで済みます。あなたのAPI。これは、リンクしたフォーラムの投稿で言及されている望ましくないオプションにかなり近いものです。完全を期すために言及し、ServletContextInitializer 部分を追加します。
2) API を にマップしたままにし/rest/*
、フィルターを使用して API の要求を識別し、そのパスに転送します。このようにして、サーブレットの URL パターン ボックスから抜け出し、任意の方法で URL を一致させることができます。たとえば、すべての REST 呼び出しが「/foo」で始まるか、正確に「/bar」であるパスに対するものであり、他のすべての要求が静的リソースに送信されると仮定すると、次のようになります。
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.regex.Pattern;
@WebFilter(urlPatterns = "/*")
public class PathingFilter implements Filter {
Pattern[] restPatterns = new Pattern[] {
Pattern.compile("/foo.*"),
Pattern.compile("/bar"),
};
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
String path = ((HttpServletRequest) request).getServletPath();
for (Pattern pattern : restPatterns) {
if (pattern.matcher(path).matches()) {
String newPath = "/rest/" + path;
request.getRequestDispatcher(newPath)
.forward(request, response);
return;
}
}
}
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void destroy() {}
}
上記では、基本的にリクエストを次のように変換します。
http://example.org/foo -> http://example.org/rest/foo
http://example.org/foox -> http://example.org/rest/foox
http://example.org/foo/anything -> http://example.org/rest/foo/anything
http://example.org/bar -> http://example.org/rest/bar
http://example.org/bart -> http://example.org/bart
http://example.org/index.html -> http://example.org/index.html
3) 前のオプションは基本的に URL 書き換えであることを認識し、Apache の mod_rewrite、Tuckey 書き換えフィルター、ocpsoft Rewriteなどの既存の実装を使用します。