各応答にヘッダーを追加する必要があります。以下にする予定です
_public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
response.addHeader("Access-Control-Allow-Origin", "*");
}
}
_
filterChain.doFilter(request, response)
の後にそれを実行して、コントローラーが処理したら、クライアントに戻る前にヘッダーを追加するだけにします。それが正しいか ?
しかし 応答フィルターの書き方?
_
chain.doFilter
_が返された後、応答で何かを行うのは遅すぎます。この時点で、応答全体がすでにクライアントに送信されており、コードはそれにアクセスできません。
上記の文は私には正しくないようです。 filterChain.doFilter(request, response)
の後にヘッダーを追加できませんか?そうでない場合、なぜですか?
spring MVCを使用しています。
後filterChain.doFilter
が呼び出されました。応答に対して何かを行うには遅すぎます。この時点で、応答全体がすでにクライアントに送信されています。
独自のクラスにラップ応答を作成し、これらのラッパーをdoFilter
メソッドに渡して、ラッパーでの処理を処理する必要があります。
拡張可能なHttpServletResponseWrapper
の応答ラッパーがすでにあります。例えば:
public class MyResponseRequestWrapper extends HttpServletResponseWrapper{
public MyResponseRequestWrapper(HttpServletResponse response) {
super(response);
}
}
あなたのフィルター:
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletResponse myResponse = (HttpServletResponse) response;
MyResponseRequestWrapper responseWrapper = new MyResponseRequestWrapper(myResponse);
responseWrapper.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, myResponse);
}
私はこれをSpring 3.0.xの私のプロジェクトで使用します:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
response.addHeader("headerName", "headerValue");
filterChain.doFilter(request, response);
}
正常に動作します。
応答を変更するフィルターは通常、クライアントに返される前に応答をキャプチャする必要があります。これを行うには、応答を生成するサーブレットにスタンドインストリームを渡します。スタンドインストリームにより、サーブレットは完了時に元の応答ストリームを閉じることができなくなり、フィルタがサーブレットの応答を変更できるようになります。
このスタンドインストリームをサーブレットに渡すために、フィルターはgetWriterまたはgetOutputStreamメソッドをオーバーライドしてこのスタンドインストリームを返す応答ラッパーを作成します。ラッパーはフィルターチェーンのdoFilterメソッドに渡されます。ラッパーメソッドは、デフォルトで、ラップされた要求または応答オブジェクトを呼び出します。このアプローチは、「デザインパターン」で説明されている有名なラッパーまたはデコレーターパターンに従います。
これは少し遅れますが、以下が役立つかもしれません。したがって、既存のヘッダーに値を追加したり、既存のヘッダーに新しい値を追加したりする場合は、ラッパーを作成してラッパーに値を設定する最良の方法です。
次に、フィルターで応答をチェーンします
HttpServletResponse response = (HttpServletResponse) servletResponse;
ByteArrayPrinter pw = new ByteArrayPrinter();
// Create a wrapper
HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
@Override
public void setContentType(final String type) {
super.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
@Override
public PrintWriter getWriter() {
return pw.getWriter();
}
// set the outputstream content type to JSON
@Override
public ServletOutputStream getOutputStream() throws IOException {
ServletResponse response = this.getResponse();
String ct = (response != null) ? response.getContentType() : null;
if (ct != null && ct.contains(APPLICATION_XHTML)) {
response.setContentType(ct + AppConstants.CONSTANT_COMMA + MediaType.APPLICATION_JSON_UTF8_VALUE);
}
return pw.getStream();
}
};
chain.doFilter(httpRequest, wrappedResp);
ここにByteArrayPrinter.Javaがあります
public class ByteArrayPrinter {
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PrintWriter pw = new PrintWriter(baos);
private ServletOutputStream sos = new ByteArrayServletStream(baos);
public PrintWriter getWriter() {
return pw;
}
public ServletOutputStream getStream() {
return sos;
}
byte[] toByteArray() {
return baos.toByteArray();
}
}
そして、これはByteArrayServletOutputStreamです
public class ByteArrayServletStream extends ServletOutputStream {
ByteArrayOutputStream baos;
ByteArrayServletStream(ByteArrayOutputStream baos) {
this.baos = baos;
}
@Override
public void write(int param) throws IOException {
baos.write(param);
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
// TODO Auto-generated method stub
}
}