1. 程式人生 > >問題解決:這個迴應response的getOutputStream()已經被呼叫過

問題解決:這個迴應response的getOutputStream()已經被呼叫過

做個登入時的驗證碼,執行時出現以下錯誤:

嚴重: Servletjsp的Servlet.service()發生意外(exception) java.lang.IllegalStateException: 這個迴應response的getOutputStream()已經被呼叫過

原始碼如下:

<%@ page language="java" contentType="image/jpeg; charset=gb2312"     pageEncoding="gb2312"%>

<%@ page import="java.awt.*,java.awt.image.*" %> 

 <%@ page import="java.util.*,javax.imageio.*" %>  

 <%!    Color getRandColor(int fc,int bc)

   Random r=new Random();  

   if(fc>255) fc=255;  

   if(bc>200) bc=255;

   int red=fc+r.nextInt(bc-fc); 

   int green=fc+r.nextInt(bc-fc);  i

   nt blue=fc+r.nextInt(bc-fc);  

   return new Color(red,green,blue);

}%>

<%  //設定頁面不快取   

   response.setHeader("Pragma","No-cache");          response.setHeader("cache-Control","no-cache");      response.setDateHeader("Expires",0);    

 //建立隨機類    

  Random r=new Random();    

 //在記憶體中建立影象,寬度,高度    

  int width=80,height=30;    

  BufferedImage pic=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);    

//獲取圖形上下文環境   

  Graphics gc=pic.getGraphics();  

 //設定背景顏色並進行填充    

  gc.setColor(getRandColor(200,250));    

  gc.fillRect(0,0,width,height);    

 //設定圖形上下文環境字型    

  gc.setFont(new Font("Times New Roman",Font.PLAIN,20));  

 //畫邊框    

 //gc.setColor(new Color(1));    

 //gc.drawRect(0,0,width-1,height-1);

//隨機產生200條幹擾直線,使影象中的認證碼不易被其他分析程式探測    

  gc.setColor(getRandColor(160,200));    

  for(int i=0;i<200;i++)    

  {      int x1=r.nextInt(width);     

         int y1=r.nextInt(height);     

         int x2=r.nextInt(15);     

         int y2=r.nextInt(15);     

        gc.drawLine(x1,y1,x1+x2,y1+y2);  

   }    

 //隨即產生100個干擾點    

  gc.setColor(getRandColor(120,240));    

  for(int i=1;i<100;i++)

  {      int x=r.nextInt(width);     

         int y=r.nextInt(height);      

         gc.drawOval(x,y,0,0);    

  }    

 //隨機產生四位數字的驗證碼    

  String RS="";     String rn="";    

  for(int i=0;i<4;i++)    

  {         //產生十以內隨機數字        

        rn=String.valueOf(r.nextInt(10));        

        RS+=rn;        

    //將認證碼用drawString函式顯示到影象裡

    //剛開始寫的沒下面這句結果字型顏色很淡幾乎看不清 

   gc.setColor(new Color(20+r.nextInt(110),20+r.nextInt(110),20+r.nextInt(110)));//使字型顏色效果明顯           gc.drawString(rn,13*i+16,16);    

 }    

 //釋放圖形上下文環境     gc.dispose();    

//將認證碼RS存入session中共享   

  session.setAttribute("random",RS);

    //輸出生成後的圖象到頁面   

ImageIO.write(pic,"JPEG",response.getOutputStream());    

 // out.clear();//清除緩衝區裡的資料,但不把資料寫到客戶端裡去

// out = pageContext.pushBody();// 重新得到out物件      

  %>

 去掉最後兩句的註釋後,就不再出錯了。原因如下:

在tomcat5下jsp中出現此錯誤一般都是在jsp中使用了輸出流(如輸出圖片驗證碼,檔案下載等),沒有妥善處理好的原因。

具體的原因就是在tomcat中jsp編譯成servlet之後在函式_jspService(HttpServletRequest request, HttpServletResponse response)的最後有一段這樣的程式碼 finally {       if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);     } 這裡是在釋放在jsp中使用的物件,會呼叫response.getWriter(),因為這個方法是和response.getOutputStream()相沖突的!所以會出現以上這個異常。

簡單的說就是web容器生成的servlet程式碼中有out.write(""),這個和JSP中呼叫的 response.getOutputStream()產生衝突.即Servlet規範說明,不能既呼叫 response.getOutputStream(), 又呼叫response.getWriter(),無論先呼叫哪一個,在呼叫第二個時候應會丟擲 IllegalStateException, 因為在jsp中,out變數實際上是通過response.getWriter得到的, 程式中既用了 response.getOutputStream,又用了out變數,故出現以上錯誤。

然後當然是要提出解決的辦法,其實挺簡單的

在使用完輸出流以後呼叫以下兩行程式碼即可: out.clear(); out = pageContext.pushBody();