Servlet3規(guī)范支持異步請(qǐng)求(或者稱為長(zhǎng)連接,或者反向AJAX,或者COMET,或者服務(wù)器推送技術(shù)):無阻塞的輸入與輸出模型,可以延時(shí)的請(qǐng)求和響應(yīng)功能,還有超時(shí)事件通知,看上去一切都是那么完美。
但終端瀏覽器支持長(zhǎng)連接情況差強(qiáng)人意,對(duì)Comet的支持大致匯總?cè)缦拢?/div>
- IE瀏覽器最佳實(shí)踐是使用htmlfile ActiveXObject,以及創(chuàng)建隱藏IFrame組件,可以跨越IE6-IE8;雖IE 8支持XDomainRequest支持HTTP Streaming,但僅僅是IE 8。
- Firefox 瀏覽器相當(dāng)棒,支持XMLHttpRequest Streaming 和隱藏的IFrame組件。
- Safari 瀏覽器支持XMLHttpRequest Streaming。
- Chrome有些無奈,算不上支持XMLHttpRequest Streaming,使用IFrame的話會(huì)一直出現(xiàn)正在加載中的標(biāo)志。
- Opera也不支持XMLHttpRequest Streaming,使用IFrame的話會(huì)一直出現(xiàn)正在加載中的標(biāo)志。
總之,使用IFrame是一個(gè)不錯(cuò)的方案,在IE、Firefox下表現(xiàn)的很完美,在其它瀏覽器下只能忍受討厭的正在加載中。數(shù)據(jù)交換格式可以采用JS腳本調(diào)用。
但無論哪一種方案,都必須認(rèn)識(shí)到,一個(gè)持久的連接,當(dāng)頁(yè)面內(nèi)容一直在遞增時(shí),會(huì)越來越膨脹,會(huì)占用用戶機(jī)器的CPU,盡量隔一段時(shí)間斷開連接,重新請(qǐng)求。
HTTP 1.1規(guī)范中聲明客戶端不應(yīng)該與服務(wù)器端建立超過兩個(gè) HTTP 連接,因此瀏覽器內(nèi)需要借助腳本避免客戶重開兩個(gè)腳本。
按照目前情形下,需要借助AJAX PULL + COMET PUSH 相結(jié)合來打造相當(dāng)好的用戶體驗(yàn)。
Servlet本身,無論2.4或者2.5的版本,可以使用一個(gè)循環(huán)達(dá)到長(zhǎng)連接的目標(biāo):
/**
* 一個(gè)典型的長(zhǎng)連接實(shí)現(xiàn)
*
* @author yongboy
* @date 2011-1-14
* @version 1.0
*/
@WebServlet("/demoLongLink")
public class DemoLongLinkServlet extends HttpServlet {
private static final long serialVersionUID = 4617227991063927036L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setHeader("Cache-Control", "private");
response.setHeader("Pragma", "no-cache");
response.setHeader("Connection", "Keep-Alive");
response.setHeader("Proxy-Connection", "Keep-Alive");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<div>Start ...</div>");
out.flush();
int num = 0;
int max = 100;
while (true) {
out.println("<div>" + (num++) + "</div>");
out.flush();
if (num >= max) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.println("<div>Done !</div>");
out.flush();
out.close();
}
}
每一個(gè)連接線程都處于一個(gè)不斷循環(huán)之中,不能夠有效釋放,相當(dāng)?shù)睦速M(fèi)服務(wù)器資源,有可能導(dǎo)致容器內(nèi)線程池耗盡,將無法應(yīng)對(duì)后續(xù)請(qǐng)求。同時(shí)少了異步連接的特性,無法直接定義超時(shí)時(shí)間,更不要說超時(shí)事件,超時(shí)監(jiān)聽器等企業(yè)特性了。
當(dāng)然也可以實(shí)現(xiàn)異步請(qǐng)求,但可能沒有規(guī)范那般嚴(yán)格。
同步請(qǐng)求的模型:
對(duì)比異步請(qǐng)求模型:
在前兩篇文章中,使用一個(gè)單獨(dú)線程處理資源,分發(fā)到大部分的異步請(qǐng)求中。