From Gossip@caterpillar

JSP/Servlet: out

 

 


在之前撰寫JSP的例子中,使用了out這個物件,這個物件您不用事先宣告,就可以在JSP網頁中使用,這是 JSP所提供的隱含物件(Implicit Object),在轉譯為Servlet之後,out會轉換為對應於javax.servlet.jsp.JspWriter型態的物件。

JspWriter直接繼承自java.io.Writer,您可以使用println()、print()方法將指定的資料以字元的方式傳送至客戶端, println()會在送出資料之後進行換行,而print()則否,注意換行指的是在HTML原始碼中設定換行字元,而不是輸出<br>標 籤使得在網頁中可以換行。

out(JspWriter)具有緩衝區功能,HTTP的特性是為了要取得一份資源,就進行一份協定溝通,如果資源數目很多(例如一份 HTML文件中還包括了許多的小圖片),而每份資源的容量實際上很小,那麼為了要取得完整的資源,將會花費很多通訊在協定往來上,假設如果out (JspWriter)不具有緩衝功能,則每一次out.println(),就會直接將資料送出至客戶端,那麼單要完成一個完整網頁的傳送,就會花費不 少的網路資源,每一個JSP網頁預設上都會具有緩衝,您可以使用page指令元素的autoFlush屬性來設定是否使用緩衝區功能。

在Tomcat 5上,預設為每一個JSP網頁備有8192位元組的緩衝區(您可以使用page指令元素的buffer屬性來自定緩衝區的大小),在緩衝區還沒有滿之前,資料不會真正被送出至客戶端,在這之前,您還有機會重設送出的資料,如果緩衝區滿了,資料將會被出清並送至客戶端,可以使用下面這個程式來示範:

  • buffer.jsp
<%@page contentType="text/html;charset=Big5"%> 
<%
out.println("預設緩衝區大小: " +
out.getBufferSize() + "<br>");
out.flush();

// 下面的文字不會出現在客戶端
out.println("您看的到這段文字嗎?");
out.clearBuffer();

out.println("這段您可以看到!");
%>

您可以使用flush()直接出清緩衝區的內容,而clearBuffer()會將緩衝區的內容清除,所以第二段文字不會出現在客戶端的網頁上,而最後一段會在整個JSP網頁執行完後自動送出至客戶端,執行結果如下:
預設緩衝區大小: 8192
這段您可以看到!
 
您可以使用page指令元素的autoFlush來設定JSP頁面是否使用緩衝區自動出清功能,out(JspWriter)以一種方式與 HttpServletResponse的PrintWriter建立關係,兩者之間的行為關係取決於是否使用緩衝區自動出清,如果使用緩衝區自動出清, 則在緩衝區滿之前,或是使用flush()之前不會建立PrintWriter物件來對客戶端進行輸出,如果不使用緩衝區自動出清,則寫入 out(JspWriter)物件的資料會直接寫入PrintWriter物件,然後在指定flush()之後輸出至客戶端。

如果您將autoFlush設定為false,則您必須明確的使用flush()來輸出資料,否則緩衝區滿了的話,就會發生 IOException例外,使用緩衝區有其好處,但由於緩衝區在滿之前,資料並不會真正送出客戶端,所以會有回應延遲的問題,如果您要即時性將結果回應 至客戶端,則可以關閉緩衝區。

下面這個程式測試緩衝區關閉之後,如果緩衝區滿了,會有什麼結果:

  • buffer.jsp
<%@page contentType="text/html;charset=Big5" 
autoFlush="false"%>
<%
for(int i = 0; i < 2000; i++) {
out.println("test");
//out.flush();
}
%>

如果沒有移開out.flush()的註解符號,則會回應以下的錯誤訊息:
HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

java.io.IOException: Error: JSP Buffer overflow
......