這個問題說來話長,我先表達一下我的觀點,Go語言從語法層面提供區(qū)分錯誤和異常的機制是很好的做法,比自己用單個返回值做值判斷要方便很多。
創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于網(wǎng)站制作、成都網(wǎng)站建設、尋烏網(wǎng)絡推廣、成都微信小程序、尋烏網(wǎng)絡營銷、尋烏企業(yè)策劃、尋烏品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)公司為所有大學生創(chuàng)業(yè)者提供尋烏建站搭建服務,24小時服務熱線:18982081108,官方網(wǎng)址:m.rwnh.cn
上面看到很多知乎大牛把異常和錯誤混在一起說,有認為Go沒有異常機制的,有認為Go純粹只有異常機制的,我覺得這些觀點都太片面了。
具體對于錯誤和異常的討論,我轉發(fā)一下前陣子寫的一篇日志拋磚引玉吧。
============================
最近連續(xù)遇到朋友問我項目里錯誤和異常管理的事情,之前也多次跟團隊強調(diào)過錯誤和異常管理的一些概念,所以趁今天有動力就趕緊寫一篇Go語言項目錯誤和異常管理的經(jīng)驗分享。
首先我們要理清:什么是錯誤、什么是異常、為什么需要管理。然后才是怎樣管理。
錯誤和異常從語言機制上面講,就是error和panic的區(qū)別,放到別的語言也一樣,別的語言沒有error類型,但是有錯誤碼之類的,沒有panic,但是有throw之類的。
在語言層面它們是兩種概念,導致的是兩種不同的結果。如果程序遇到錯誤不處理,那么可能進一步的產(chǎn)生業(yè)務上的錯誤,比如給用戶多扣錢了,或者進一步產(chǎn)生了異常;如果程序遇到異常不處理,那么結果就是進程異常退出。
在項目里面是不是應該處理所有的錯誤情況和捕捉所有的異常呢?我只能說,你可以這么做,但是估計效果不會太好。我的理由是:
如果所有東西都處理和記錄,那么重要信息可能被淹沒在信息的海洋里。
不應該處理的錯誤被處理了,很容易導出BUG暴露不出來,直到出現(xiàn)更嚴重錯誤的時候才暴露出問題,到時候排查就很困難了,因為已經(jīng)不是錯誤的第一現(xiàn)場。
所以錯誤和異常最好能按一定的規(guī)則進行分類和管理,在第一時間能暴露錯誤和還原現(xiàn)場。
對于錯誤處理,Erlang有一個很好的概念叫速錯,就是有錯誤第一時間暴露它。我們的項目從Erlang到Go一直是沿用這一設計原則。但是應用這個原則的前提是先得區(qū)分錯誤和異常這兩個概念。
錯誤和異常上面已經(jīng)提到了,從語言機制層面比較容易區(qū)分它們,但是語言取決于人為,什么情況下用錯誤表達,什么情況下用異常表達,就得有一套規(guī)則,否則很容易出現(xiàn)全部靠異常來做錯誤處理的情況,似乎Java項目特別容易出現(xiàn)這樣的設計。
這里我先假想有這樣一個業(yè)務:游戲玩家通過購買按鈕,用銅錢購買寶石。
在實現(xiàn)這個業(yè)務的時候,程序邏輯會進一步分化成客戶端邏輯和服務端邏輯,客戶端邏輯又進一步因為設計方式的不同分化成兩種結構:胖客戶端結構、瘦客戶端結構。
胖客戶端結構,有更多的本地數(shù)據(jù)和懂得更多的業(yè)務邏輯,所以在胖客戶端結構的應用中,以上的業(yè)務會實現(xiàn)成這樣:客戶端檢查緩存中的銅錢數(shù)量,銅錢數(shù)量足夠的時候購買按鈕為可用的亮起狀態(tài),用戶點擊購買按鈕后客戶端發(fā)送購買請求到服務端;服務端收到請求后校驗用戶的銅錢數(shù)量,如果銅錢數(shù)量不足就拋出異常,終止請求過程并斷開客戶端的連接,如果銅錢數(shù)量足夠就進一步完成寶石購買過程,這里不繼續(xù)描述正常過程。
因為正常的客戶端是有一步數(shù)據(jù)校驗的過程的,所以當服務端收到不合理的請求(銅錢不足以購買寶石)時,拋出異常比返回錯誤更為合理,因為這個請求只可能來自兩種客戶端:外掛或者有BUG的客戶端。如果不通過拋出異常來終止業(yè)務過程和斷開客戶端連接,那么程序的錯誤就很難被第一時間發(fā)現(xiàn),攻擊行為也很難被發(fā)現(xiàn)。
我們再回頭看瘦客戶端結構的設計,瘦客戶端不會存有太多狀態(tài)數(shù)據(jù)和用戶數(shù)據(jù)也不清楚業(yè)務邏輯,所以客戶端的設計會是這樣:用戶點擊購買按鈕,客戶端發(fā)送購買請求;服務端收到請求后檢查銅錢數(shù)量,數(shù)量不足就返回數(shù)量不足的錯誤碼,數(shù)量足夠就繼續(xù)完成業(yè)務并返回成功信息;客戶端收到服務端的處理結果后,在界面上做出反映。
在這種結構下,銅錢不足就變成了業(yè)務邏輯范圍內(nèi)的一種失敗情況,但不能提升為異常,否則銅錢不足的用戶一點購買按鈕都會出錯掉線。
所以,異常和錯誤在不同程序結構下是互相轉換的,我們沒辦法一句話的給所有類型所有結構的程序一個統(tǒng)一的異常和錯誤分類規(guī)則。
但是,異常和錯誤的分類是有跡可循的。比如上面提到的痩客戶端結構,銅錢不足是業(yè)務邏輯范圍內(nèi)的一種失敗情況,它屬于業(yè)務錯誤,再比如程序邏輯上嘗試請求某個URL,最多三次,重試三次的過程中請求失敗是錯誤,重試到第三次,失敗就被提升為異常了。
所以我們可以這樣來歸類異常和錯誤:不會終止程序邏輯運行的歸類為錯誤,會終止程序邏輯運行的歸類為異常。
因為錯誤不會終止邏輯運行,所以錯誤是邏輯的一部分,比如上面提到的瘦客戶端結構,銅錢不足的錯誤就是業(yè)務邏輯處理過程中需要考慮和處理的一個邏輯分支。而異常就是那些不應該出現(xiàn)在業(yè)務邏輯中的東西,比如上面提到的胖客戶端結構,銅錢不足已經(jīng)不是業(yè)務邏輯需要考慮的一部分了,所以它應該是一個異常。
錯誤和異常的分類需要通過一定的思維訓練來強化分類能力,就類似于面向對象的設計方式一樣的,技術實現(xiàn)就擺在那邊,但是要用好需要不斷的思維訓練不斷的歸類和總結,以上提到的歸類方式希望可以作為一個參考,期待大家能發(fā)現(xiàn)更多更有效的歸類方式。
接下來我們講一下速錯和Go語言里面怎么做到速錯。
速錯我最早接觸是在做的時候就體驗到的,當然跟Erlang的速錯不完全一致,那時候也沒有那么高大上的一個名字,但是對待異常的理念是一樣的。
在.NET項目開發(fā)的時候,有經(jīng)驗的程序員都應該知道,不能隨便re-throw,就是catch錯誤再拋出,原因是異常的第一現(xiàn)場會被破壞,堆棧跟蹤信息會丟失,因為外部最后拿到異常的堆棧跟蹤信息,是最后那次throw的異常的堆棧跟蹤信息;其次,不能隨便try catch,隨便catch很容易導出異常暴露不出來,升級為更嚴重的業(yè)務漏洞。
到了Erlang時期,大家學到了速錯概念,簡單來講就是:讓它掛。只有掛了你才會第一時間知道錯誤,但是Erlang的掛,只是Erlang進程的異常退出,不會導致整個Erlang節(jié)點退出,所以它掛的影響層面比較低。
在Go語言項目中,雖然有類似Erlang進程的Goroutine,但是Goroutine如果panic了,并且沒有recover,那么整個Go進程就會異常退出。所以我們在Go語言項目中要應用速錯的設計理念,就要對Goroutine做一定的管理。
在我們的游戲服務端項目中,我把Goroutine按掛掉后的結果分為兩類:1、掛掉后不影響其他業(yè)務或功能的;2、掛掉后業(yè)務就無法正常進行的。
第一類Goroutine典型的有:處理各個玩家請求的Goroutine,因為每個玩家連接各自有一個Goroutine,所以掛掉了只會影響單個玩家,不會影響整體業(yè)務進行。
第二類Goroutine典型的有:數(shù)據(jù)庫同步用的Goroutine,如果它掛了,數(shù)據(jù)就無法同步到數(shù)據(jù)庫,游戲如果繼續(xù)運行下去只會導致數(shù)據(jù)回檔,還不如讓整個游戲都異常退出。
這樣一分類,就可以比較清楚哪些Goroutine該做recover處理,哪些不該做recover處理了。
那么在做recover處理時,要怎樣才能盡量保留第一現(xiàn)場來幫組開發(fā)者排查問題原因呢?我們項目中通常是會在最外層的recover中把錯誤和堆棧跟蹤信息記進日志,同時把關鍵的業(yè)務信息,比如:用戶ID、來源IP、請求數(shù)據(jù)等也一起記錄進去。
為此,我們還特地設計了一個庫,用來格式化輸出堆棧跟蹤信息和對象信息,項目地址:funny/debug · GitHub
通篇寫下來發(fā)現(xiàn)比我預期的長很多,所以這里我做一下歸納總結,幫組大家理解這篇文章所要表達的:
錯誤和異常需要分類和管理,不能一概而論
錯誤和異常的分類可以以是否終止業(yè)務過程作為標準
錯誤是業(yè)務過程的一部分,異常不是
不要隨便捕獲異常,更不要隨便捕獲再重新拋出異常
Go語言項目需要把Goroutine分為兩類,區(qū)別處理異常
在捕獲到異常時,需要盡可能的保留第一現(xiàn)場的關鍵數(shù)據(jù)
以上僅為一家之言,拋磚引玉,希望對大家有所幫助。
本教程介紹了 Go 中模糊測試的基礎知識。通過模糊測試,隨機數(shù)據(jù)會針對您的測試運行,以嘗試找出漏洞或導致崩潰的輸入??梢酝ㄟ^模糊測試發(fā)現(xiàn)的一些漏洞示例包括 SQL 注入、緩沖區(qū)溢出、拒絕服務和跨站點腳本攻擊。
在本教程中,您將為一個簡單的函數(shù)編寫一個模糊測試,運行 go 命令,并調(diào)試和修復代碼中的問題。
首先,為您要編寫的代碼創(chuàng)建一個文件夾。
1、打開命令提示符并切換到您的主目錄。
在 Linux 或 Mac 上:
在 Windows 上:
2、在命令提示符下,為您的代碼創(chuàng)建一個名為 fuzz 的目錄。
3、創(chuàng)建一個模塊來保存您的代碼。
運行go mod init命令,為其提供新代碼的模塊路徑。
接下來,您將添加一些簡單的代碼來反轉字符串,稍后我們將對其進行模糊測試。
在此步驟中,您將添加一個函數(shù)來反轉字符串。
a.使用您的文本編輯器,在 fuzz 目錄中創(chuàng)建一個名為 main.go 的文件。
獨立程序(與庫相反)始終位于 package 中main。
此函數(shù)將接受string,使用byte進行循環(huán) ,并在最后返回反轉的字符串。
此函數(shù)將運行一些Reverse操作,然后將輸出打印到命令行。這有助于查看運行中的代碼,并可能有助于調(diào)試。
e.該main函數(shù)使用 fmt 包,因此您需要導入它。
第一行代碼應如下所示:
從包含 main.go 的目錄中的命令行,運行代碼。
可以看到原來的字符串,反轉它的結果,然后再反轉它的結果,就相當于原來的了。
現(xiàn)在代碼正在運行,是時候測試它了。
在這一步中,您將為Reverse函數(shù)編寫一個基本的單元測試。
a.使用您的文本編輯器,在 fuzz 目錄中創(chuàng)建一個名為 reverse_test.go 的文件。
b.將以下代碼粘貼到 reverse_test.go 中。
這個簡單的測試將斷言列出的輸入字符串將被正確反轉。
使用運行單元測試go test
接下來,您將單元測試更改為模糊測試。
單元測試有局限性,即每個輸入都必須由開發(fā)人員添加到測試中。模糊測試的一個好處是它可以為您的代碼提供輸入,并且可以識別您提出的測試用例沒有達到的邊緣用例。
在本節(jié)中,您將單元測試轉換為模糊測試,這樣您就可以用更少的工作生成更多的輸入!
請注意,您可以將單元測試、基準測試和模糊測試保存在同一個 *_test.go 文件中,但對于本示例,您將單元測試轉換為模糊測試。
在您的文本編輯器中,將 reverse_test.go 中的單元測試替換為以下模糊測試。
Fuzzing 也有一些限制。在您的單元測試中,您可以預測Reverse函數(shù)的預期輸出,并驗證實際輸出是否滿足這些預期。
例如,在測試用例Reverse("Hello, world")中,單元測試將返回指定為"dlrow ,olleH".
模糊測試時,您無法預測預期輸出,因為您無法控制輸入。
但是,Reverse您可以在模糊測試中驗證函數(shù)的一些屬性。在這個模糊測試中檢查的兩個屬性是:
(1)將字符串反轉兩次保留原始值
(2)反轉的字符串將其狀態(tài)保留為有效的 UTF-8。
注意單元測試和模糊測試之間的語法差異:
(3)確保新包unicode/utf8已導入。
隨著單元測試轉換為模糊測試,是時候再次運行測試了。
a.在不進行模糊測試的情況下運行模糊測試,以確保種子輸入通過。
如果您在該文件中有其他測試,您也可以運行go test -run=FuzzReverse,并且您只想運行模糊測試。
b.運行FuzzReverse模糊測試,查看是否有任何隨機生成的字符串輸入會導致失敗。這是使用go test新標志-fuzz執(zhí)行的。
模糊測試時發(fā)生故障,導致問題的輸入被寫入將在下次運行的種子語料庫文件中go test,即使沒有-fuzz標志也是如此。要查看導致失敗的輸入,請在文本編輯器中打開寫入 testdata/fuzz/FuzzReverse 目錄的語料庫文件。您的種子語料庫文件可能包含不同的字符串,但格式相同。
語料庫文件的第一行表示編碼版本。以下每一行代表構成語料庫條目的每種類型的值。由于 fuzz target 只需要 1 個輸入,因此版本之后只有 1 個值。
c.運行沒有-fuzz標志的go test; 新的失敗種子語料庫條目將被使用:
由于我們的測試失敗,是時候調(diào)試了。
查找Web服務器漏洞
在Web服務器等非定制產(chǎn)品中查找漏洞時,使用一款自動化掃描工具是一個不錯的起點。與Web應用程序這些定制產(chǎn)品不同,幾乎所有的Web服務器都使用第三方軟件,并且有無數(shù)用戶已經(jīng)以相同的方式安裝和配置了這些軟件。
在這種情況下,使用自動化掃描器發(fā)送大量專門設計的請求并監(jiān)控表示已知漏洞的簽名,就可以迅速、高效地確定最明顯的漏洞。Nessus 是一款優(yōu)良的免費漏洞掃描器,還有各種商業(yè)掃描器可供使用,如 Typhon 與 ISS。
除使用掃描工具外,滲透測試員還應始終對所攻擊的軟件進行深入研究。同時,瀏覽Security Focus、郵件列表Bugtrap和Full Disclosure等資源,在目標軟件上查找所有最近發(fā)現(xiàn)的、尚未修復的漏洞信息。
還要注意,一些Web應用程序產(chǎn)品中內(nèi)置了一個開源Web服務器,如Apache或Jetty。因為管理員把服務器看作他們所安裝的應用程序,而不是他們負責的基礎架構的一部分,所以這些捆綁服務器的安全更新也應用得相對較為緩慢。而且,在這種情況下,標準的服務標題也已被修改。因此,對所針對的軟件進行手動測試與研究,可以非常有效地確定自動化掃描工具無法發(fā)現(xiàn)的漏洞。
新聞名稱:go語言漏洞怎么找 go語言遇到的坑
本文路徑:http://m.rwnh.cn/article44/doshehe.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供關鍵詞優(yōu)化、定制網(wǎng)站、、域名注冊、網(wǎng)站設計、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)