如何删除静态资源的Orchestra converstation上下文参数? [英] How to remove Orchestra converstation context parameter for static resources?

查看:97
本文介绍了如何删除静态资源的Orchestra converstation上下文参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了提供适当的浏览器缓存,我想摆脱conversationContext参数,Apache MyFaces Orchestra将它添加到每个对CSS文件的请求中的请求.

按照 Bozho 的建议,我已经实现了一个过滤器,该过滤器设置了Orchestra正在寻找的属性.

public class ResourceFilter implements Filter {

@Override
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException {
    if(shouldNotAppendConversation(request)) {
        request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE);
    }

    theChain.doFilter(request, theResponse);
}

private boolean shouldNotAppendConversation(ServletRequest theRequest) {
    HttpServletRequest aRequest = (HttpServletRequest) theRequest;
    String aPath = aRequest.getRequestURI();
    if(aPath.endsWith(".css.jsf")) {
        return true;
    }

    return false;
}

@Override
public void init(FilterConfig theFilterConfig) throws ServletException {
}

@Override
public void destroy() {
}
}

那不起作用,该参数仍附加到每个请求中.调试时,我发现该过滤器首先被发送到jsf站点的请求.当然,我想在该请求中包含conversation context,因此过滤器将请求直接转发到链中的下一个过滤器.命中过滤器的下一个请求(通常是对CSS文件的请求)已经包含在请求中.

public class RfOrchestraParamControlFilter implements Filter {
   ...
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
      chain.doFilter(request, response);
   }
   ...
}

.

奇怪的是,如果我将过滤器修改为始终设置属性 ,则所有请求都将不具有conversation context属性.但这意味着conversation context也不包含在jsf网站的请求中(但应该).

我注意到,在jsf站点的生成的html中,指向css文件的链接也包含conversation context属性,取决于过滤器的实现.我想因为这个原因,第二个请求已经包含了conversation context参数?

我不明白为什么Orchestra会将conversation context参数附加到每个请求,而不仅仅是未设置属性的请求.

如何实现过滤器才能正常工作?

解决方案

下一个请求(例如,对于CSS文件)在您对页面的请求中已经包含了conversationContext参数后,仅在过滤器中出现,这是因为该资源的url已由上一个请求中的页面呈现.

因此,对conversationContext的控制应在渲染时进行.以下解决方案适用于JSF 2(我正在使用Mojarra 2.1.11,myfaces-orchestra-core20 1.5,RichFaces 4.1.0.Final).特殊的servlet过滤器除了将HttpServletResponse用我们自己的包装器包装之外,什么也不做:

public class RfOrchestraParamControlFilter implements Filter {
   ...
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
      chain.doFilter(request, response);
   }
   ...
}

响应包装器测试要被编码为成为Richfaces资源的网址并转换乐团的在编码时,ConversationRequestParameterProvider的分离模式在当前线程中处于打开状态:

package ...
import javax.faces.application.ResourceHandler;
import org.richfaces.resource.ResourceHandlerImpl;
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider;

public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper {

   public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) {
      super(httpServletResponse);
   }

   @Override
   public String encodeURL(String url) {
      if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) {
         boolean current = ConversationRequestParameterProvider.isInSeparationMode();
         /* Disable conversationContext parameter in current thread for the time of rendering link to a resource */
         ConversationRequestParameterProvider.setInSeparationMode(true);

         String result = super.encodeURL(url);

         /* Restore */
         ConversationRequestParameterProvider.setInSeparationMode(current);
         return result;
      }
      else return super.encodeURL(url);
   }

}

(当测试URL作为资源时,我不得不使用String.contains()而不是String.startsWith(),因为上下文路径和servlet路径恰好在传递的URL之前.)

但是,此刻也无济于事.原因是管弦乐队使用了它自己的响应包装,该包装在其RequestParameterFacesContextFactory中发生,并且这种包装发生在我们的过滤器被点击后 .这样,Orchestra的包装器就位于我们的包装器的外部,这导致我们的包装器收到url时为时已晚,这是因为该URL已被拦截并附加了conversationContext.

为避免这种情况,我们可以通过将RequestParameterFacesContextFactory拦截器的效果替换为RequestParameterServletFilter实际上是Bozho suggested, I've implemented a filter that sets the attribute Orchestra is looking for.

public class ResourceFilter implements Filter {

@Override
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException {
    if(shouldNotAppendConversation(request)) {
        request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE);
    }

    theChain.doFilter(request, theResponse);
}

private boolean shouldNotAppendConversation(ServletRequest theRequest) {
    HttpServletRequest aRequest = (HttpServletRequest) theRequest;
    String aPath = aRequest.getRequestURI();
    if(aPath.endsWith(".css.jsf")) {
        return true;
    }

    return false;
}

@Override
public void init(FilterConfig theFilterConfig) throws ServletException {
}

@Override
public void destroy() {
}
}

That doesn't work the parameter is still appended to every request. While debugging, I've found out that the filter gets first hit by a request to the jsf site. For sure I want to include the conversation context in that request, so the filter forwards the request directly to the next filter in the chain. The next request that hits the filter (usually the request for a css file) has already the conversation context included in the request.

The strange thing is, if I modify the filter to always set the attribute, all request will not have the conversation context attribute. But that means, the conversation context is also not included in the request for the jsf site (but should).

I've noticed that the links to css files in the generated html of the jsf site also contains the conversation context attribute or not depending on the filter implementation. I guess for this reason the second request has already included the conversation context parameter?

I don't understand why Orchestra is appending the conversation context parameter to every request and not just for the requests where the attribute is not set.

How can I implement the filter to work correctly?

解决方案

The next request (e.g. for a CSS file) hitting your filter after the request to your page has already the conversationContext parameter included just because this is how the url for this resource has been rendered by the page in the previous request.

So the control over conversationContext should be taken at render time. The following solution is working for me with JSF 2 (I am using Mojarra 2.1.11, myfaces-orchestra-core20 1.5, RichFaces 4.1.0.Final). A special servlet filter is doing nothing but wraps HttpServletResponse with our own wrapper:

public class RfOrchestraParamControlFilter implements Filter {
   ...
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
      response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response);
      chain.doFilter(request, response);
   }
   ...
}

The response wrapper tests the url to be encoded for being a richfaces resource and turns Orchestra's ConversationRequestParameterProvider's separation mode on in the current thread for the time of encoding:

package ...
import javax.faces.application.ResourceHandler;
import org.richfaces.resource.ResourceHandlerImpl;
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider;

public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper {

   public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) {
      super(httpServletResponse);
   }

   @Override
   public String encodeURL(String url) {
      if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) {
         boolean current = ConversationRequestParameterProvider.isInSeparationMode();
         /* Disable conversationContext parameter in current thread for the time of rendering link to a resource */
         ConversationRequestParameterProvider.setInSeparationMode(true);

         String result = super.encodeURL(url);

         /* Restore */
         ConversationRequestParameterProvider.setInSeparationMode(current);
         return result;
      }
      else return super.encodeURL(url);
   }

}

(I've had to use String.contains() instead of String.startsWith() when testing the url for being a resource as context path and servlet path happen to prepend the passed url.)

However that does not help either by this moment. The reason is that Orchestra uses its own response wrapping that takes place in its RequestParameterFacesContextFactory, and this wrapping happens after our filter is hit. In this way Orchestra's wrapper turns out to be external to our one which results in our wrapper receiving url too late, when the url has already been intercepted and conversationContext appended.

To avoid this we have a way to make our response wrapper external to Orchestra's one by replacing effect from RequestParameterFacesContextFactory interceptor with RequestParameterServletFilter which actually does the same work. Unfortunately using another filter is not quite exquisite where we might not, but I don't see another way so far.

So, in web.xml place your filter after Orchestra's one:

<filter>
   <filter-name>requestParameterFilter</filter-name>
   <filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class>
</filter>
<filter>
   <filter-name>myOrchestraFilter</filter-name>
   <filter-class>mypkg.RfOrchestraParamControlFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>requestParameterFilter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<filter-mapping>
   <filter-name>myOrchestraFilter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

这篇关于如何删除静态资源的Orchestra converstation上下文参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆