获取'无法设置标题。响应已经使用primefaces fileupload进行了提交

时间:2014-02-27 13:49:47

标签: jsf-2 primefaces websphere-8

我在 websphere 8.5.0.1 上使用jsf 2( javax.faces-2.0.10.jar )和 primefaces 3.5 我也在使用文件上传jar:

  • 公地文件上传-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.

请告知文件上传无效的原因?

2 个答案:

答案 0 :(得分:0)

显然,您的响应已在抛出异常的行之前提交。我还没有看到你在那里找到的具体例子,但问题很常见,并且有一种通用的方法可以跟踪这些问题。在您预期之前会有一些内容写入您的响应,但您看到的堆栈跟踪是针对稍后尝试添加到该响应的事件。因此,解决方案是在提交响应时记录堆栈跟踪 ,然后在抛出异常的稍后时刻,打印第一个堆栈跟踪。

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

在我们的真实&#39;代码,我记录了堆栈跟踪并仅在问题发生时打印出来,如上所述,但下面的代码只是在提交响应时记录,你可以通过查看你的日志找出哪一个。

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中的空白和内容类型设置可以很容易地推动你超过缓冲区限制,你可能没有意识到你写了任何东西。例如,特别是执行<%@ page contentType="text/html; charset=UTF-8"%>之类但后转到另一个servlet的jsps是错误的。
  • 设置大型Cookie。 Cookie是标题,因此计入缓冲区大小
  • servlet过滤器。有些应用程序有大量的这些,可能过于急于编写标题。

答案 1 :(得分:0)

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