servlet3.1規範: 第5章 響應(Response)
響應
響應(response)物件封裝了從伺服器返回到客戶端的所有資訊。在HTTP協議中,從伺服器傳輸到客戶端的資訊通過HTTP頭資訊或響應的訊息體。
5.1 緩衝區
Servlet容器允許但不必為了提高效率而緩衝到客戶端的輸出。電信的伺服器預設都是緩衝的,但允許servlet指定緩衝引數。
ServletResponse介面的如下方法允許servlet訪問和設定緩衝資訊:
■getBufferSize
■setBufferSize
■ isCommitted
■ reset
■ resetBuffer
■ flushBuffer
不管Servlet使用的是一個ServletOutputStream還是一個Writer,ServletResponse介面提供的這些方法允許執行緩衝操作。
getBufferSize方法返回使用的底層緩衝區大小。如果沒有使用緩衝,該方法必須返回一個int值0。
Servlet可以請求setBufferSize方法設定一個最佳的緩衝大小。不一定分配servlet請求大小的緩衝區,但至少與請求的大小一樣大。這允許容器重用一組固定大小的緩衝區,如果合適,可以提供一個比請求時更大的緩衝區。該方法必須在使用ServletOutputStream 或Writer寫任何內容之前呼叫。如果已經寫了內容或響應物件已經提交,則該方法必須丟擲IllegalStateException。
isCommitted方法返回一個表示是否有任何響應位元組已經返回到客戶端的boolean值。flushBuffer方法強制刷出緩衝區的內容到客戶端。
當響應沒有提交時,reset方法清空緩衝區的資料。頭資訊,狀態碼和在呼叫reset之前servlet呼叫getWriter或getOutputStream設定的狀態也必須被清空。
如果響應沒有被提交,resetBuffer方法將清空緩衝區中的內容,但不清空請求頭和狀態碼。
如果響應已經提交併且reset或resetBuffer方法已被呼叫,則必須丟擲IllegalStateException,響應及它關聯的緩衝區將保持不變。
當使用緩衝區時,容器必須立即刷出填滿的緩衝區內容到客戶端。如果這是最早傳送到客戶端的資料,且認為響應被提交了。
5.2 頭資訊
Servlet可以使用如下HttpServletResponse介面中的方法設定HTTO響應頭:
■ setHeader
■ addHeader
setHeader方法設定一個給定名字和值的header。之前的header將被新的header替換。如果已經存在同名的header值的set,set中的值會被清空並用新的值替換。
addHeader方法使用給定的名字新增一個header值到set。如果沒有header與給定的名字關聯,則建立一個新的set。
Header可能包含表示int或Date物件的資料。以下HttpServletResponse介面提供的便利方法允許Servlet對適當的資料型別用正確的格式設定一個header:
■ setIntHeader
■setDateHeader
■ addIntHeader
■addDateHeader
為了成功的傳回給客戶端,header必須在響應提交前設定。響應提交後的Header設定將被servlet容器忽略。
Servlet程式設計師負責保證為Servlet生成的內容設定合適的response物件的Content-Type header。HTTP 1.1規範中沒有要求在HTTP響應中設定此header。當Servlet程式設計師沒有設定該型別時,Servlet容器也不能設定預設的內容型別。
建議容器使用X-Powered-ByHTTP header公佈它的實現資訊。該欄位值應考慮一個或多個實現型別,如”Servlet/3.0”。容器應該可以配置來隱藏該header。可選的容器補充的資訊和底層Java平臺可以被放在括號內並新增到實現型別之後。
X-Powered-By: Servlet/3.1
X-Powered-By: Servlet/3.1 JSP/2.2(GlassFish v3 JRE/1.6.0)
5.3 非阻塞IO
為了支援在Servlet容器中的非阻塞寫,除了在3-28頁3.7節描述的“非阻塞IO” 對ServletRequest做的更改之外,下面做出的更改以便於處理響應相關的類/介面。
WriteListener 提供瞭如下適用於容器呼叫的回撥方法。
The WriteListener provides the followingcallback methods which the container invokes appropriately.
■WriteListener
■ voidonWritePossible(). 當一個WriteListener註冊到ServletOutputStream時,當且僅當下邊描述的ServletOutputStream的canWrite方法被呼叫並返回false,該容器將回調該方法。
■ onError(Throwablet). 當處理響應過程中出現錯誤時回撥。
除了WriteListener外,還有如下方法被新增到ServletOutputStream類並允許開發人員執行時檢查是否可以寫資料傳送到客戶端。
■ServletOutputStream
■ booleancanWrite(). 如果往ServletOutputStream寫會成功,則該方法返回true,其他情況會返回false。如果該方法返回true,可以在ServletOutputStream 上執行寫操作。如果沒有後續的資料能寫到ServletOutputStream,那麼直到底層的資料被刷出之前該方法將一直返回false。且在此時容器將呼叫WriteListener的onWritePossible方法。隨後呼叫該方法將返回true。
■ voidsetWriteListener(WriteListener listener). 關聯WriteListener和當且的ServletOutputStream,當ServletOutputStream可以寫入資料時容器會呼叫WriteListener的回撥方法。註冊了WriteListener將開始非阻塞IO。此時再切換到傳統的阻塞IO是非法的。
5.4 簡便方法
HttpServletResponse提供瞭如下簡便方法:
■ sendRedirect
■ sendError
sendRedirect方法將設定適當的header和內容體將客戶端重定向到另一個地址。使用相對URL路徑呼叫該方法是合法的,但是底層的容器必須將傳回到客戶端的相對地址轉換為全路徑URL。無論出於什麼原因,如果給定的URL是不完整的,且不能轉換為一個有效的URL,那麼該方法必須丟擲IllegalArgumentException。
sendError方法將設定適當的header和內容體用於返回給客戶端返回錯誤訊息。可以sendError方法提供一個可選的String引數用於指定錯誤的內容體。
如果響應已經提交併終止,這兩個方法將對提交的響應產生負作用。這兩個方法呼叫後servlet將不會產生到客戶端的後續的輸出。這兩個方法呼叫後如果有資料繼續寫到響應,這些資料被忽略。如果資料已經寫到響應的緩衝區,但沒有返回到客戶端(例如,響應沒有提交),則響應緩衝區中的資料必須被清空並使用這兩個方法設定的資料替換。如果想要已提交,這兩個方法必須丟擲IllegalStateException。
5.5 國際化
Servlet應設定response的locale和字符集。使用ServletResponse.setLocale方法設定locale。該方法可以重複的呼叫;但響應被提交後呼叫該方法不會產生任何作用。如果在頁面被提交之前Servlet沒有設定locale,容器的預設locale將用來確定響應的locale,但是沒有制定與客戶端通訊的規範,例如使用HTTP情況下的Content-Language header。
<locale-encoding-mapping-list>
<locale-encoding-mapping>
<locale>ja</locale>
<encoding>Shift_JIS</encoding>
</locale-encoding-mapping>
</locale-encoding-mapping-list>
如果該元素不存在或沒有提供mapping,setLocale使用容器依賴的mapping。setCharacterEncoding,setContentType和setLocale方法可以被重複的呼叫來改變字元編碼。如果在servlet 響應的getWriter方法已經呼叫之後或響應被提交之後,呼叫相關方法設定字元編碼將沒有任何作用。只有當給定的content type字串提供了一個charset屬性值,呼叫setContentType可以設定字元編碼。只有當既沒有呼叫setCharacterEncoding也沒有呼叫setContentType去設定字元編碼之前呼叫setLocale可以設定字元編碼。
在ServletResponse介面的getWriter方法被呼叫或響應被提交之前,如果servlet沒有指定字元編碼,預設使用ISO-8859-1。
如果使用的協議提供了一種這樣做的方式,容器必須傳遞servlet 響應的writer使用的locale和字元編碼到客戶端。使用HTTP的情況下,locale可以使用Content-Language header傳遞,字元編碼可以作為用於指定文字媒體型別的Content-Typeheader的一部分傳遞。注意,如果沒有指定content type,字元編碼不能通過HTTP header傳遞;但是仍使用它來編碼通過servlet 響應的writer寫的文字。
5.6 結束響應物件
當響應被關閉時,容器必須立即刷出響應緩衝區中的所有剩餘的內容到客戶端。
以下事件表明servlet滿足了請求且響應物件即將關閉:
■ servlet的service方法終止。
■ 響應的setContentLength或setContentLengthLong方法指定的內容量大於零並且已經寫入到響應。
■ sendError 方法已呼叫。
■ sendRedirect方法已呼叫。
■ AsyncContext的complete 方法已呼叫。
5.7 響應物件的生命週期
每個響應物件是隻有當在servlet的service方法的範圍內或在filter的doFilter方法範圍內是有效的,除非該元件關聯的請求物件已經開啟非同步處理。如果相關的請求已經啟動非同步處理,那麼直到AsyncContext的complete方法被呼叫,請求物件一直有效。為了避免響應物件建立的效能開銷,容器通常回收響應物件。在相關的請求的startAsync還沒有呼叫時,開發人員必須意識到保持到響應物件引用,超出之上描述的範圍可能導致不確定的行為。