我为应用程序编写了一个小型CMS,该应用程序提供了基本的站点管理功能,例如所见即所得内容和模板编辑。页面以facelets的形式存储在数据库中,并使用自定义的URL解析器呈现给客户端(请参见https://community.jboss.org/message/495515#495515上的最后一篇文章),在我开始为同一应用程序所服务的不同域支持不同的页面树之前,它的工作原理非常好。像apache的虚拟主机)。

因此,http://firstdomain/cms/page.xhtml应该导致与http://seconddomain/cms/page.xhtml不同的页面。这里的问题是,由我的自定义DefaultResourceResolver(以及其他任何解析器)解析的URL仅由JSF使用路径(/cms/page.xhtml)进行缓存。因此,无论首先查询哪个域,都为与同一路径无关的所有请求提供所有URL的缓存URL。

我花了相当长的时间将这个问题归结到缓存上,但是现在我被卡住了。有什么方法可以更改/覆盖/禁用JSF的URL缓存以尊重所请求的域名吗?

更新1:我刚刚阅读了FaceletCacheImpl.java的myfaces实现,并注意到URL本身是其缓存的关键,而不仅仅是其路径的关键。这导致这里讨论的问题:Why does java.net.URL's hashcode resolve the host to an IP?-使用URL的IP地址而不是主机名来比较URL。因此,我仍然必须更改Facelets缓存行为。

更新2:尝试使用URL参数使我确信,除了FaceletCacheImpl.java中看到的内容之外,它们确实仅通过其路径进行了缓存,因此可以忽略更新1。

最佳答案

更多的研究将我指向DefaultFaceletFactory.java,它负责调用已注册的URL解析器并缓存已解析的URL。由于该类是最后的类,因此无法扩展它,因此我从jboss下载了最新的jsf-facelets源,并通过将当前请求主机附加到缓存键来直接对其进行了修改。这是我的public Facelet getFacelet(String uri)替代品:

public static HttpServletRequest getRequest() {
    return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
}

/**
 * Returns the host name from the current request.
 *
 * @return
 */
public static String getRequestHost() {
    HttpServletRequest request = getRequest();
    if (request == null) {
        return null;
    }
    String result = request.getHeader("x-forwarded-host");
    if (result == null || result.isEmpty()) {
        result = request.getHeader("host");
    }
    return result;
}


/*
 * (non-Javadoc)
 *
 * @see com.sun.facelets.FaceletFactory#getFacelet(java.lang.String)
 */
public Facelet getFacelet(String uri) throws IOException, FaceletException,
        FacesException, ELException {
    String key = getRequestHost() + ":" + uri;
    URL url = (URL) this.relativeLocations.get(key);
    if (url == null) {
        url = this.resolveURL(this.baseUrl, uri);
        if (url != null) {
            Map newLoc = new HashMap(this.relativeLocations);
            newLoc.put(key, url);
            this.relativeLocations = newLoc;
        } else {
            throw new IOException("'" + uri + "' not found.");
        }
    }
    return this.getFacelet(url);
}


我必须承认,这种解决方案很脏,但是可以完成工作。另外,一段时间以来,facelets的实现没有任何变化,因此更新应该不是问题。

10-07 18:55
查看更多