Java Servlet响应包装器存在编码问题

Java Servlet响应包装器存在编码问题,java,servlets,character-encoding,wrapper,servlet-filters,Java,Servlets,Character Encoding,Wrapper,Servlet Filters,servlet响应包装器正在servlet筛选器中使用。其思想是,响应被操纵,将“nonce”值注入表单中,作为抵御CSRF攻击的一部分 这个web应用程序到处都在使用UTF-8。当Servlet过滤器不存在时,没有问题。添加筛选器时,会出现编码问题。(似乎回复为8859-1。) 代码的核心: final class CsrfResponseWrapper extends AbstractResponseWrapper { ... byte[] modifyResponse(byte

servlet响应包装器正在servlet筛选器中使用。其思想是,响应被操纵,将“nonce”值注入表单中,作为抵御CSRF攻击的一部分

这个web应用程序到处都在使用UTF-8。当Servlet过滤器不存在时,没有问题。添加筛选器时,会出现编码问题。(似乎回复为8859-1。)

代码的核心:

final class CsrfResponseWrapper extends AbstractResponseWrapper {
   ...
   byte[] modifyResponse(byte[] aInputResponse){
      ...
      String originalInput = new String(aInputResponse, encoding);
      String modifiedResult = addHiddenParamToPostedForms(originalInput);
      result = modifiedResult.getBytes(encoding);
      ...
   }
   ...
}
据我所知,字节区域和字符串区域之间的转换应该指定编码。正如你所看到的,这是在两个地方完成的。“encoding”变量的值为“UTF-8”;字符串本身的更改是标准的字符串操作(使用正则表达式),并且从不指定编码(addHiddenParamToPostedForms)

我在编码方面哪里出错了

编辑: 这是基类(抱歉,太长了):


您提供的代码似乎没有错误

你在别处干什么

  • 链中是否有其他过滤器可能操纵编码/字节流,可能是过滤器位置有问题
  • “编码”是修复还是动态读取请求
来自:

从现有OutputStream创建新的PrintWriter,无需自动换行。这个方便的构造函数创建必要的中间OutputStreamWriter,它将使用默认字符编码将字符转换为字节


那是你的罪魁祸首。查看可以指定编码的位置。

链中还有两个其他筛选器:一个用于抑制无关会话,另一个用于执行与用户登录相关的任务。两者都不会改变响应流。“编码”项已修复。没有明显的问题。你确定,如果UTF-8没有通信,通信是在UTF-8上的吗?您的包装器是否正确地转发了编码设置?非常肯定,是的。Firefox在响应头中显示UTF-8;我的JSP都保存在UTF-8中。无论我在哪里引用标记文件,我似乎都会在输出中得到“?”字符。而且,当不存在有问题的筛选器时,我可以看到阿拉伯语字符fine.FYI-基类可能是可疑的。是的,这解决了问题。在本教程中的样式之后,我修改并简化了代码:
package hirondelle.web4j.security;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 Abstract Base Class for altering response content.
 (May be useful in future contexts as well. For now, keep package-private.)  
*/
abstract class AbstractResponseWrapper extends HttpServletResponseWrapper {

  AbstractResponseWrapper(ServletResponse aServletResponse) throws IOException {
    super((HttpServletResponse)aServletResponse);
    fOutputStream = new ModifiedOutputStream(aServletResponse.getOutputStream());
    fWriter = new PrintWriter(fOutputStream);
  }

  /** Return the modified response. */
  abstract byte[] modifyResponse(byte[] aInputResponse);

  /** Standard servlet method.  */
  public final ServletOutputStream getOutputStream() {
    //fLogger.fine("Modified Response : Getting output stream.");
    if ( fWriterReturned ) {
      throw new IllegalStateException();
    }
    fOutputStreamReturned = true;
    return fOutputStream;
  }

  /** Standard servlet method.  */
  public final PrintWriter getWriter() {
    //fLogger.fine("Modified Response : Getting writer.");
    if ( fOutputStreamReturned ) {
      throw new IllegalStateException();
    }
    fWriterReturned = true;
    return fWriter;
  }

  // PRIVATE

  /*
   Well-behaved servlets return either an OutputStream or a PrintWriter, but not both.
  */
  private PrintWriter fWriter; 
  private ModifiedOutputStream fOutputStream;

  /*
   These items are used to implement conformance to the 
   javadoc for ServletResponse, regarding exceptions being thrown.
  */
  private boolean fWriterReturned;
  private boolean fOutputStreamReturned;

  /** Modified low level output stream.  */
  private class ModifiedOutputStream extends ServletOutputStream {
    public ModifiedOutputStream(ServletOutputStream aOutputStream) {
      fServletOutputStream = aOutputStream;
      fBuffer = new ByteArrayOutputStream();
    }
    /** Must be implemented to make this class concrete.   */
    public void write(int aByte) {
      fBuffer.write(aByte);
    }
    public void close() throws IOException {
      if ( !fIsClosed ){
        processStream();
        fServletOutputStream.close();
        fIsClosed = true;
      }
    }
    public void flush() throws IOException {
      if ( fBuffer.size() != 0 ){
        if ( !fIsClosed ) {
          processStream(); 
          fBuffer = new ByteArrayOutputStream();
        }
      }
    }
    /** Perform the core processing, by calling the abstract method.  */
    public void processStream() throws IOException {
      fServletOutputStream.write(modifyResponse(fBuffer.toByteArray()));
      fServletOutputStream.flush();
    }
    // PRIVATE //
    private ServletOutputStream fServletOutputStream;
    private ByteArrayOutputStream fBuffer;
    /** Tracks if this stream has been closed.    */
    private boolean fIsClosed = false;
  }
}