一次難忘的調試經歷

正在編一個網站,在本地編好以後打包成war遠程部署到tomcat。在本地一切正常,可是一傳到服務器上去就不行了。
我這個網站程序會訪問一個網頁,去那個網頁上爬取點東西,要想爬取就必須須要data.txt提供令牌。
初步鎖定bug所在區間,編一個小程序測試一下java

@RequestMapping("haha")
    @ResponseBody
    String debug() {
        try {
            return Util.debug("SY1606604", "xxxxxx", HttpClients.createDefault());
        } catch (IOException e) {
            e.printStackTrace(); 
        }  
        return "error";
    }

出錯的那段代碼原來是Util.login(username,password,client)
我把出錯的那段代碼重寫,寫成一個函數叫作Util.debug(),讓這個函數返回儘可能多的信息
結果

怎麼會這樣呢?我寫了ResponseBody了呀,返回不得是個字符串嗎?不會跳到「error」頁面的呀。
那我就多返回一點數據:小程序

@RequestMapping("haha")
    @ResponseBody
    String debug() {
        StringBuilder builder = new StringBuilder();
        try {
            builder.append(Util.debug("SY1606604", "xxxxx", HttpClients.createDefault()));
        } catch (IOException e) {
            builder.append(e.getMessage());
            builder.append(e.getCause().toString());
            builder.append(e.toString());
            builder.append("不可能出錯呀");
           
        } 
         return "error";
    }

訪問haha頁面,結果發現仍是上面那種狀況,一點都沒變啊!
爲何呀?
原來是錯中有錯,在catch中再次拋出了異常!我又沒寫finally,結果這個Servlet就向容器拋出異常,結果就跳轉到error頁面去了!
還有,若是是運行時異常,catch IOException好像不會接住吧,因此改爲接一切異常!再加上一個finallytomcat

StringBuilder builder = new StringBuilder();
        try {
            builder.append(Util.debug("SY1606604", "xxxxx", HttpClients.createDefault()));
        } catch (Exception e) {
            builder.append(e.getMessage());
            builder.append(e.getCause().toString());
            builder.append(e.toString());
            builder.append("不可能出錯呀");
        } finally {
            return builder.toString();
        }

結果頁面中一個字都沒有,ctrl+u查看網頁源代碼,也是空空如也。這tm都是咋回事啊?
要知道上面每一次試錯都須要進行服務器

  • maven package打包
  • 打開tomcat manager頁面,undeploy舊的war
  • 選擇新的war,點擊deploy
  • 等待上傳結束,刷新haha頁面

每次至少兩分鐘。
我怒了,我打印了這麼多東西爲啥一個字都沒有?
重定向,接受一切打印!!!!!!!!app

@RequestMapping("haha")
    @ResponseBody
    String debug() {
        StringBuilder builder = new StringBuilder();
        builder.append("百思不得其解");
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream stream = new PrintStream(out);
        try {
            System.setErr(stream);
            System.setOut(stream);
            builder.append(Util.debug("SY1606604", "xxxxx", HttpClients.createDefault()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            builder.append(out.toString());
            return builder.toString();
        }
    }

終於:

終於看到了日誌,求之不得的日誌,終於知道本身錯在哪裏?當我看到找不到data.txt文件這句話時,我差點哭出來,好艱難。
珍惜日誌,哪有那麼多條件去讓你調試、跟蹤,根本不可能。連部署都是這麼艱難,就像ACM題同樣,只告訴你對錯bool值,不告訴你錯在哪裏,這是最使人瘋狂的。
彷彿有一個聲音不停地在耳邊呼喊:「你不行的」,我一直追問:「爲何不行?我哪裏不行?」這個聲音彷彿在嘲笑:「你爲何不行,我不說」。這就像是完全的否認。
不斷地向別人展現別人沒法更改的錯誤,是一種邪惡。它只是爲了指出錯誤而指出錯誤,只是無理由的告訴你你不行。這讓人如墮深淵。
別人有錯誤,若是以讓其改正爲目的,則是善意;若是隻是一次簡單的評判,則是中意;若是是指出別人錯誤彰顯本身的明智或者羞辱別人,那這就是惡意。maven

回到上文,這裏的錯誤是找不到data.txt,代碼中是這麼寫的:函數

OutputStream cout = Files.newOutputStream(Paths.get("src/main/resources/checkcode.jpg"));

路徑有問題,由於一旦部署到服務器,就沒有這種路徑了!應該去掉src/main/resources/這個前綴,由於在maven打包時自動把resources目錄下的東西打包到classpath路徑中了。更好的解決方法是:使用classPath而不要使用操做系統的文件路徑測試

回頭觀望,我發現了一種調試程序的手段。
定義一個攔截器,在進行處理請求以前,重定向輸出流、錯誤流或者日誌到一個內存流,在請求處理的最後,若是發現錯誤,則打印這個流。這樣就能清楚知道本身錯在哪裏了。網站

相關文章
相關標籤/搜索