2014-02-27 28 views
0

我使用JSF 2(javax.faces-2.0.10.jar)和primefaces 3.5的WebSphere 8.5.0.1,我也使用文件上传罐子:获取'无法设置标题。已经承诺”与primefaces响应文件上传

  • 公地文件上传-1.3.1.jar
  • 公地IO-2.4.jar

,我试图用primefaces FileUpload组件如下:

<h:form id="frm" enctype="multipart/form-data"> 
     <p:fileUpload id="fileUpload" value="#{uploadDocument.file}" 
     fileUploadListener="#{uploadDocument.handleFileUpload}" mode="advanced" dragDropSupport="false" 
        sizeLimit="10000000" fileLimit="3" /> 
     </h:form> 

的web.xml配置:

<filter> 
     <filter-name>PrimeFaces FileUpload Filter</filter-name> 
     <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class> 
     <init-param> 
      <param-name>uploadDirectory</param-name> 
      <param-value>C:/uploadFolder</param-value> 
     </init-param> 
    </filter> 

    <filter-mapping> 
     <filter-name>PrimeFaces FileUpload Filter</filter-name> 
     <servlet-name>Faces Servlet</servlet-name> 
    </filter-mapping> 

    <servlet> 
     <servlet-name>Faces Servlet</servlet-name> 
     <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> 
     <load-on-startup>1</load-on-startup> 
    </servlet> 

    <servlet-mapping> 
     <servlet-name>Faces Servlet</servlet-name> 
     <url-pattern>/faces/*</url-pattern> 
    </servlet-mapping> 

    <servlet-mapping> 
     <servlet-name>Faces Servlet</servlet-name> 
     <url-pattern>*.jsf</url-pattern> 
    </servlet-mapping> 

选择文件并单击上传后,该文件没有上传,我在日志文件中得到以下警告:

com.ibm.ws.webcontainer.srt.SRTServletResponse addHeader SRVE8094W: WARNING: Cannot set header. Response already committed. 

请指教为什么文件上传不起作用?

+1

最可能的一个错误。尝试升级你的JSF和PF版本 – kolossus

+1

你在'web.xml'中有另一个'Servlet Filter'配置? – CycDemo

回答

0

问题是因为我在我的类路径上有一个名为appbase.jar的jar,当我删除它时,一切正常。

0

显然你的回应已经在投掷异常之前被提交。我还没有看到你在那里得到的具体例子,但是这个问题很常见,并且有一种通用的方法来追踪这些问题。有些东西正在写入您的回复之前,但是您看到的堆栈跟踪是为了稍后尝试添加到该回复中的事件。因此,解决方案是在响应提交时记录堆栈跟踪,然后在抛出异常的稍后时间点打印此第一个堆栈跟踪。

我没有我以前用来做这件事的代码,就像我为以前的公司写的那样。我在下面提出了一个大纲解决方案,它显示了它的要点 - 您需要包装响应,以及它返回的任何servletoutputstream/printwriter对象来检测提交事件。我已经展示了如何通过使用自省来做到这一点;但如果您愿意的话,您可以使用ServletResponseWrapper和自定义的包装类作为流/写入器。事实上,你不需要像我这样做包装许多方法。

在我们的“真实”代码中,我记录了堆栈跟踪并只在上述问题发生时才打印,但下面的代码只是在提交响应时记录日志,您可以通过查看日志。

public class BadCommitFilter implements Filter { 
    public void doFilter(ServletRequest req, ServletResponse res, 
     FilterChain chain) throws IOException, ServletException { 

     HttpServletResponse response = (HttpServletRequest) res; 
     response=Proxy.newProxyInstance(this.getClass().getClassLoader(), 
       new Class[] { HttpServletResponse.class }, 
       new ResponseInvocationHandler(response, response)); 
     chain.doFilter(req, response); 
    } 
    private static class ResponseInvocationHandler<T> implements InvocationHandler { 
     final T proxied; 
     final HttpServletResponse response; 

     public ResponseInvocationHandler(T proxied, HttpServletResponse response) { 
     this.proxied = proxied; 
     this.response = response; 
     } 

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     // in the 'real' code, I checked against a threadlocal 
     // at the end only, so there was no possibility that I'd 
     // miss out methods. 
     boolean isCommitted = res.isCommitted(); 
     try { 
      Object ret = method.invoke(proxied, args); 
      if (ret instanceof PrintWriter) { 
      Proxy.newProxyInstance(ret.getClass().getClassLoader(), 
       new Class[] { PrintWriter.class }, 
       new ResponseInvocationHandler(ret, response)); 
      } else if (ret instanceof ServletOutputStream) { 
      Proxy.newProxyInstance(ret.getClass().getClassLoader(), 
       new Class[] { ServletOutputStream.class }, 
       new ResponseInvocationHandler(ret, response)); 
      } 
     } finally { 
      if(!isCommitted && res.isCommitted()) { 
      try { throw Exception("First Committed:"); } 
      // or however you want to log this 
      catch(Exception e){e.printStackTrace();}    
      } 
     } 
     return ret; 
     } 
    } 
} 

如果你在代码方面有问题,有一些常见的嫌疑人要查找。记住承诺可以明确触发,但更多的时候是因为你已经写入了足够的数据到缓冲区,所以必须刷新:

  • 使用jsp分派到一个servlet。 jsps中的空白和内容类型设置可以很容易地将你超过缓冲区限制,你可能没有意识到你会写任何东西。特别是jsps,它可以执行任何类似于<%@ page contentType="text/html; charset=UTF-8"%>的任何操作,但是转发到另一个servlet是错误的。
  • 设置大型饼干。 Cookie是标题,所以计算缓冲区大小
  • servlet过滤器。有些应用程序拥有大量的这些应用程序,可能会急于编写标题。