「ヘッダーを設定できません。」というメッセージが表示されます。primefaces fileupload で「応答はすでにコミットされました」
-
23-12-2019 - |
質問
私はjsf 2を使用しています(javax.faces-2.0.10.jar) そして プライムフェイス 3.5 の上 ウェブスフィア 8.5.0.1 そして私はファイルアップロードjarも使用しています:
- commons-fileupload-1.3.1.jar
- commons-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
問題は私がそれを削除したときに私のクラスパスにappbase.jar
と呼ばれるjarを持っていたためでした。
他のヒント
明らかに、応答は例外をスローする行の前にコミットされています。そこにある具体的な例は見ていませんが、この問題は非常に一般的なものであり、これらを追跡する一般的な方法があります。予期される前に応答に何かが書き込まれていますが、表示されるスタックトレースは、その応答に追加しようとしている後のイベントのものです。したがって、解決策はスタックトレースを記録することです 応答がコミットされたとき, その後、例外がスローされた時点で、この最初のスタックトレースも出力します。
以前の会社のために書いたコードなので、これを行うために使用していたコードは手元にありません。以下にソリューションの概要を示します。これはその要点を示しています。コミット イベントを検出するには、応答とそれが返すサーブレット出力ストリーム/プリントライター オブジェクトをラップする必要があります。イントロスペクションを使用してこれがどのように行われるかを示しました。ただし、必要に応じて、ストリーム/ライターに 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 を使用してサーブレットにディスパッチします。jsps の空白とコンテンツ タイプの設定により、バッファ制限を簡単に超えてしまう可能性があり、何も書いたことに気づかない可能性があります。たとえば、特に次のようなことを行う jsps
<%@ page contentType="text/html; charset=UTF-8"%>
しかし、別のサーブレットに転送するのは間違っています。 - 大きなクッキーを設定します。Cookie はヘッダーであるため、バッファ サイズにカウントされます。
- サーブレットフィルター。一部のアプリにはこれらの膨大なスタックがあり、ヘッダーを書き込むことに過度に熱心になる可能性があります。