從HttpServletResponse裏拿到PrintWriter的內容

在JavaWeb企業級應用中,接口是一個很常見的功能模塊。此處不討論以下問題(請自行搜索):git

  • 接口是什麼
  • 爲何要使用接口
  • .....

通常的接口代碼中會有以下代碼片斷(此處省略接收參數、處理異常請求等功能代碼):程序員

PrintWriter writer = null;
    try {
        writer = response.getWriter();
        String msg = "<xml><msg>hahah</msg><createAt>"
                +System.currentTimeMillis()+"</createAt></xml>";
        writer.print(msg);
        writer.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (writer != null) {
            writer.close();
        }
    }

很簡單,如上代碼將msg的內容響應給請求者,請求者將獲取到msg的內容。apache

幾天前遇到一個問題,要在Struts2框架中使用攔截器,來截取請求報文與響應報文。(我的認爲該功能應該由核心處理器去統一完成。)不論可否實現,且試一下。tomcat

上面的代碼中很明顯將一個字符串放在response裏響應給請求者。那咱們能不能在這裏作文章呢。 Debug一下writer的值看能不能有什麼線索。框架

咱們能夠在writer.flush()以後添加點代碼:eclipse

PrintWriter writer = null;
    try {
        writer = response.getWriter();
        String msg = "<xml><msg>hahah</msg><createAt>"
                +System.currentTimeMillis()+"</createAt></xml>";
        writer.print(msg);
        writer.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (writer != null) {
            writer.close();
        }
    }
    
    try {
            PrintWriter writerToBeRead = response.getWriter();
            System.out.print(writerToBeRead.getClass().getName());                
    } catch (Exception e) {
        e.printStackTrace();
    }

咱們在ide

System.out.print(writerToBeRead.getClass().getName());

這一行添加斷點進行調試。 正好看到了要響應給請求者的信息。.net

PrinterWriter

能夠看到區域3中存放的信息就是msg,它的內容在區域5中清晰地顯示着。而區域3是區域2的成員屬性(其實區域4這個對象也和區域2同樣)。debug

最重要的是輸出的內容調試

org.apache.catalina.connector.CoyoteWriter

正好咱們在上圖的區域1中看到了

"writerToBeRead"=CoyoteWriter

說明writerToBeRead這個對象是org.apache.catalina.connector.CoyoteWriter類型的。若是您瞭解tomcat源代碼,能夠知道該類在TOMCAT_BASE/lib/catalina.jar中,這個jar由tomcat主程序調用,不被程序員顯式使用,因此在添加dependency時添加provided類型的scope,因爲它還會引入coyote.jar文件,故也將其排除。

<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>catalina</artifactId>
    <version>6.0.45</version>
   <scope>provided</scope>  
    <exclusions>
        <exclusion>
            <artifactId>coyote</artifactId>
            <groupId>org.apache.tomcat</groupId>
        </exclusion>
    </exclusions>
</dependency>

而後咱們就將writerToBeRead強制轉換成CoyoteWriter

PrintWriter writerToBeRead = response.getWriter();
    CoyoteWriter cw = (CoyoteWriter)writerToBeRead;

而後在eclipse中按ctrl點擊CoyoteWriter,能夠看到它有一個受保護的成員屬性ob

CoyoteWriter

下面要進行的就是——反射了。 先取出ob的內容,代碼以下 :

Class<?> clazz = cw.getClass();
        Field declaredField = clazz.getDeclaredField("ob");
        declaredField.setAccessible(true);
        OutputBuffer ob = (OutputBuffer)declaredField.get(cw);

一樣點擊OutputBuffer,能夠看到它有一個私有屬性outputChunk

OutputBuffer

無論三七二十一,拿出來再說。

Class<?> classOutputBuffer = ob.getClass();
        Field fieldOutputChunk = classOutputBuffer.getDeclaredField("outputChunk");
        fieldOutputChunk.setAccessible(true);
        Object object = fieldOutputChunk.get(ob);
        System.out.println("text from response: "+ object);

哈,咱們拿到想要的數據了。

多說一句,上面的object的類型是`org.apache.tomcat.util.buf.ByteChunk`,感興趣的能夠看下tomcat源碼,瞭解下它的toString()方法或其它的,tomcat真的是大師級做品啊。

博客也至此結束了。 歡迎參觀個人博客,拍磚~。

  • 提供項目文件:http://git.oschina.net/valuetodays/blog-attachment/raw/master/oschina/%E4%BB%8EHttpServletResponse%E9%87%8C%E6%8B%BF%E5%88%B0PrintWriter%E7%9A%84%E5%86%85%E5%AE%B9/getDataFromResponse.zip

  • 提供源文件內容:

    public void doGetDataFromResponse(HttpServletResponse response) {
              PrintWriter writer = null;
              try {
                  writer = response.getWriter();
                  String msg = "<xml><msg>hahah</msg><createAt>"
                          +System.currentTimeMillis()+"</createAt></xml>";
                  writer.print(msg);
                  writer.flush();
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  if (writer != null) {
                      writer.close();
                  }
              }
    
              try {
                  PrintWriter writerToBeRead = response.getWriter();
                  System.out.print(writerToBeRead.getClass().getName());
                  CoyoteWriter cw = (CoyoteWriter)writerToBeRead;
                  LOG.debug(cw.getClass().getName());
                  Class<?> clazz = cw.getClass();
                  Field declaredField = clazz.getDeclaredField("ob");
                  declaredField.setAccessible(true);
                  OutputBuffer ob = (OutputBuffer)declaredField.get(cw);
                  LOG.debug(ob);
                  Class<?> classOutputBuffer = ob.getClass();
                  Field fieldOutputChunk = classOutputBuffer.getDeclaredField("outputChunk");
                  fieldOutputChunk.setAccessible(true);
                  Object object = fieldOutputChunk.get(ob);
                  LOG.info(object.getClass().getName());
                  LOG.info("text from response: "+ object);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
相關文章
相關標籤/搜索