我们想要构建一个单一的代理 servlet,它将服务于许多不同的路径,例如
/api/注册
/api/播放器/1234/
/api/播放器/12312/交易
基本上,/api/下面的所有路径
目前我们正在使用这种模式,它只允许单个或固定路径列表:
@SlingServletPaths(value="/bin/somepath")
private class MyServlet extends SlingAllMethodsServlet
关于如何处理变量路径有什么建议吗?
我在这里找到了一个使用自定义 ResourceResolver 的潜在解决方案,但不幸的是它无法编译(注释和导入等在 AEM 6.5 中不再可用):
你不能用 Sling-Servlets 做到这一点。但是您可以在 Sling MainServlet 旁边有一个 OSGi Whiteboard-Pattern Servlet。最简单的情况是使用与 Sling 相同的上下文名称(因为 Sling 已经注册了整个 URL 空间)
详情请参考: https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.http.whiteboard.html
我也喜欢为一些外部服务使用代理 servlet(例如 Solr、Commerce-System 等)。对于开发来说,它比在每台开发人员机器上设置额外的基础设施要简单得多。
但是:
PS: scope=PROTOTYPE 对 HttpWhiteboard 服务很重要
@Component(service = Servlet.class, scope = ServiceScope.PROTOTYPE)
@HttpWhiteboardServletPattern("/api/*")
@HttpWhiteboardContextSelect("(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=org.apache.sling)")
public class OsgiProxyServlet extends HttpServlet {
public static final Logger LOGGER = LoggerFactory.getLogger(OsgiProxyServlet.class);
private final Semaphore semaphore;
@Activate
public OsgiProxyServlet() {
this.semaphore = new Semaphore(/* max. parallel requests */ 5, true);
LOGGER.info("Proxy Servlet instantiated");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
LOGGER.info("Got API Request: {}", request.getRequestURL());
boolean permitAcquired = false;
try {
permitAcquired = semaphore.tryAcquire(/* timeout */ 500, TimeUnit.MILLISECONDS);
if (permitAcquired) {
doProxyGet(request, response);
} else {
respond(response, SC_REQUEST_TIMEOUT, "Failed to acquire a proxy connection");
}
} catch (InterruptedException e) {
// in the Servlet.doGet()-method we cannot propagate the InterruptedException,
// so we have to set the flag back to true
Thread.currentThread().interrupt();
} finally {
if (permitAcquired) {
semaphore.release();
}
}
}
private void doProxyGet(HttpServletRequest request, HttpServletResponse response) {
// put your proxy code here
LOGGER.info("Proxy request {}", request.getRequestURI());
respond(response, SC_OK, "Proxy request for path " + request.getPathInfo());
}
private static void respond(HttpServletResponse response, int status, String message) {
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.setStatus(status);
try {
response.getWriter().print(message);
} catch (IOException e) {
LOGGER.error("Failed to write output", e);
}
}
}
这是一个工作的 ServletFilter,您要求的(有关更多信息,请参阅 https://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.http.whiteboard.html):
@Component(scope = ServiceScope.PROTOTYPE)
@HttpWhiteboardFilterPattern("/api/*")
@HttpWhiteboardContextSelect("(" + HTTP_WHITEBOARD_CONTEXT_NAME + "=org.apache.sling)")
public class OsgiFilter implements Filter {
@Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) {
// empty
}
@Override
public void destroy() {
// empty
}
}