1. 程式人生 > >解決了一個Web網頁顯示不全的BUG

解決了一個Web網頁顯示不全的BUG

一【BUG描述】

最近開發一個Web系統的過程中遇到了一個詭異的BUG,花了2天時間解決,感覺如釋重負。

這個BUG的現象是這樣的:一個很普通的JSP網頁,本來顯示很正常,後來我在這個html頁面上加了一些控制元件元素,並修改了下CSS, JavaScript程式碼,並加入了些中文字元。本來是覺得沒什麼問題,可是在伺服器上跑起來就發現瀏覽器上這個頁面顯示一片空白,同時其他頁面卻顯示正常。另外,我用的Tomcat版本是8.0.17。

那麼我第一反應就是這個頁面程式碼哪裡改錯了,可是我仔細看了下覺得又沒什麼問題,然後頁面字元編碼和Content-type都是顯示設定UTF-8編碼。看來前端好像沒什麼問題,然後我就在瀏覽器上檢視頁面原始碼,結果發現瀏覽器上顯示的HTML原始碼居然不完整,html頁面尾部的4~5行程式碼全部不見了。這就是導致頁面無法正常顯示的直接原因。

這個無非就兩種可能:瀏覽器資料沒有全部接收,或者伺服器資料沒有全部發送。這時,我就用WireShark抓包觀察,結果顯示tomcat伺服器在傳送資料時最後幾行資料根本就沒有傳送過來。而且這兒非常巧合,因為html資料以chunked的方式傳送,最後那幾行資料恰好應該全部在最後的一個chunked包裡面,換句話說,就是最後一個chunked包丟了。

為啥偏偏這個頁面的最後一個chunked包丟了,而其他頁面好好的呢?

這時沒別的辦法啦,只能一步一步除錯JSP頁面程式碼咯(這個耗費了我1天多的時間)。通過觀察其他正常顯示的JSP頁面與這個出問題的JSP頁面的執行流程,我發現問題出在:JSP頁面在tomcat中輸出的時候,最後一個chunked資料包在快取中沒有被flush。

二【定位】

為啥不flush?這個多種原因造成的:

  1. JSP頁面在通過JspWriter輸出之後,其實還留了點在快取裡面。以前一般是在JSP執行完,銷燬PageContext的時候將快取中的資料flush到網路流上,可現在作者為了提高網路效能,只是將資料flush到了較低一層的CoyoteWriter的快取中,等到整個請求-響應過程結束,再flush到網路流上。如下圖:            
  2. 作者想法是不錯,可惜少算了一步。CoyoteWriter物件是通過一個org.apache.catalina.connector.OutputBuffer來完成資料輸出的。這個OutputBuffer物件有個suspended(暫停)標誌位,用來隨時暫停這個輸出物件,處於暫停狀態的OutputBuffer物件是不會進行資料輸出的。tomcat在完成JspWriter輸出的工作後,提前將OutputBuffer的狀態設定為suspended狀態,這一步的意思防止響應資料輸出之後又輸出其他不該輸出的資料。這個本意是好的,可是等到整個過程結束,關閉OutputBuffer物件的時候,就因為這個suspended狀態導致close這個函式還沒來得及執行flush就直接退出了。如下圖: 
                為啥別的頁面沒有這個情況,偏偏這個Html頁面就出現問題了?這個情況有點複雜:
  1. 當頁面通過OutputBuffer輸出第1個chunked包的資料的時候,這個物件偷偷將這個chunked包的字元資料轉換成二進位制資料快取了起來,並沒有真正輸出到網路流中。只有等到要輸出第二個chunked包的時候,才flush快取,將第一個包的資料輸出到網路中,為第二個chunked包騰出足夠的快取空間,並快取第二個chunked包。
  2. 當OutputBuffer輸出第一個chunked資料包到網路中的時候,會搶先輸出的Http 響應頭,並將response物件的commited標誌設定為true(這就表示響應頭已經發送)。
  3. 在ErrorReportValve.invoke函式中,處理完http請求後,會判斷response物件的commited標誌是否為true,如果不是true,則將OutputBuffer的suspended標誌設定為false,保證響應資料能夠輸出。
  4. 好了,原因找到了:因為其他web網頁比較小,導致jsp頁面處理結束了,所有的chunked資料還在緩衝中,完全並沒有被輸出到網路中(一部分在OutputBuffer快取中,一部分在JspWriter快取中),commited標誌此時為false,等到ErrorReportValve處理時,根據commited標誌,將suspended標誌重置為false,這樣在最後關閉OutputBuffer的時候,就將所有這些快取中的資料一個個都flush到了網路上。相反,我修改的那個網頁比較大,導致OutputBuffer中途就將部分資料flush到了網路上,是的commited標誌位true,那麼ErrorReportValve也就不會將suspended標誌重置為false,導致OutputBuffer在關閉時,並不會flush殘留在快取中的資料。

三【解決】

如何解決這個bug?
  1. 在JSP頁面最後加<% out.flush %>強制重新整理;
  2. 升級或者回退Tomcat 伺服器版本;
後面的Tomcat(8.0.23)版本是怎麼解決這個bug的? 在StandardHostValve.invoke函式中加了一行程式碼,重置OutputBuffer的suspended標誌為false,這樣就可以保證關閉OutputBuffer時,flush殘留在快取中的資料了。如下圖:            

相關推薦

解決一個Web網頁顯示BUG

一【BUG描述】 最近開發一個Web系統的過程中遇到了一個詭異的BUG,花了2天時間解決,感覺如釋重負。 這個BUG的現象是這樣的:一個很普通的JSP網頁,本來顯示很正常,後來我在這個html頁面上加了一些控制元件元素,並修改了下CSS, JavaScript程式碼,並加入

【最強解決辦法】列印圖片顯示

最近寫論文,由於學會要求PDF稿內的圖片大於300dpi,於是在word那兒折騰了半天。 有人推薦用LaTeX類軟體來寫作,那樣匯出畫質啊格式啊啥的都可調,而且完美……但是抱歉我只有3天時間了,來不及學這麼個用程式設計思維來寫文章的軟體。於是下列問題如何解決呢? 1. Word2013預覽裡的圖片

關於如何解決PHPCMS V9內容搜索顯示問題解決方案

復制 site OS search 關於 module bool ole 顯示不全 進入到phpcms/modules/search/index.php文件。 找到以下代碼: if(!empty($segment_q)) { $sql = “`siteid`= ‘$site

iOS:解決UITextView自適應高度粘貼大量文字導致顯示的問題

tex 顯示 輸入框 textview size self. uitext sel lec 一、描述 在UITextView輸入框中粘貼大量的文字時,UITextView內容自適應高度計算出現誤差,導致整塊文字上移消失。 二、方案 在UITextView文字改變的監聽中

【Python學習】解決pandas中打印DataFrame行列顯示的問題

需要 pandas pre pytho 如果 clas panda 顯示不全 可能 在使用pandas的DataFrame打印時,如果表太長或者太寬會自動只給前後一些行列,但有時候因為一些需要,可能想看到所有的行列。 所以只需要加一下的代碼就行了。 #顯示所有列 pd.se

IE8中select控制元件中的option顯示解決方案

 select控制元件,若option的內容過長,則IE8中顯示不全,導致其內容無法顯示出來。  目前測試IE9、IE11 select控制元件都沒有問題。 其中select,可以只針對個別的select,只要替換相應的class即可。  解決方案:

Echarts 折線圖y軸標籤值太長時顯示解決辦法

問題 分析 解決辦法 問題 先看一下正常的情況 再看一下顯示不全的情況 所有的資料都是從後臺取的,也就是說動態變化的,一開始的時

ScoreView巢狀Listview或GradView顯示問題解決

public class ListviewUtil { public static void setListViewHeightBasedOnChildren(ListView listView) { // 獲取ListView對應的Adapter

JavaScript解決select下拉框中的內容太長顯示的問題

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

pandas中關於DataFrame行,列顯示(省略)的解決辦法

有時候DataFrame中的行列數量太多,print打印出來會顯示不完全。就像下圖這樣: 列顯示不全: 行顯示不全: 新增如下程式碼,即可解決。 #顯示所有列 pd.set_option('display.max_columns', None) #顯示所有行 pd.set_opt

android全面屏顯示解決方案【更新中...】

一、宣告最大螢幕縱橫比(官方適配方案) Android官方提供了適配方案,即提高App所支援的最大螢幕縱橫比,實現很簡單,在AndroidManifest.xml中可做如下配置: <meta-data android:name="android.max_aspect"

C#中使用DataGridView列資訊顯示解決方式

在datagridview中,將讀取到的xls表格中的資料顯示出來了,但是有一部分字沒顯示出來,非要去點下,效果如下: 然後excel中的資料是這樣的: 我想要datagridview中的資料看起來一目瞭然,像excel表格那樣,就是k9後面的4個數字也顯示全,調整

解決 select2 開啟 tags 輸入中文顯示BUG

一、急著修復,不求甚解: 直接開啟 select2.full.min.js 內容複製到 https://tool.lu/js/ 點選【美化(Beutify)】按鈕,格式化一下方便閱讀。 格式化好後,搜尋 “em” 會找到如下這段程式碼 : .--------------

解決ECharts 因X軸類目過多導致重疊顯示的問題

https://blog.csdn.net/zheng_xiao_xin/article/details/80882113         dataZoom : [//橫向滾動條         

ScrollView巢狀ListView,顯示和位置是頂部的解決辦法

(1)首先寫一個listview的頁面,用ScrollView進行巢狀,注意ScrollView裡面只能有一個佈局屬性,多個可以用Linearout進行包含 <?xml version="1.0" encoding="utf-8"?> <RelativeL

修改DEDECMS文章標題長度,解決DEDECMS文章標題顯示

在用dede呼叫列表標題出來的時候,會發現標題文字字數顯示不完全,那是因為dede預設標題出來長度是30個字元,為了讓標題顯示完整,要做以下修改! 1、進入後臺–系統–系統設定–系統基本引數–其他選項–文件標題最大程度改為你要的長度原預設是60(這裡改為了20

android listview巢狀時,顯示能滑動的解決

在listview巢狀listview的過程中,如果我們不寫一點特殊的操作的話,可能子listview會顯示不全,並且無法滑動,那麼應該怎麼解決呢 1.子listview繼承listview,然後重寫onmeasure方法,在裡面手動的去計算高度,然後傳給super方法,這

Eclipse Maven構建WebApp專案資源目錄顯示的原因與解決方式

一、問題展示        1、Eclipse在使用Maven構建WebApp專案的時候,首先Maven的安裝和配置都沒有問題的,但是構建專案之後,Maven專案要求的幾個必須要有的資源目錄顯示不了:

swift3.0 tableviewcell分割線顯示解決方案

在viewDidLoad()新增一下程式碼 if tableView.responds(to:#selector(setter: UITableViewCell.separatorInset))

簡單解決RecyclerView巢狀的RecyclerView條目顯示和寬度能鋪滿

第一個RecyclerView的Adapter @Override public MyHolder onCreateViewHolder(ViewGroup parent, int viewT