云和安全管理服務(wù)專家新鈦云服 張春翻譯
葉集ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18982081108(備注:SSL證書合作)期待與您的合作!
這種方法有幾個(gè)缺點(diǎn)。首先,它可以對(duì)程序員隱藏錯(cuò)誤處理路徑,特別是在捕獲異常不是強(qiáng)制性的情況下,例如在 Python 中。即使在具有必須處理的 Java 風(fēng)格的檢查異常的語(yǔ)言中,如果在與原始調(diào)用不同的級(jí)別上處理錯(cuò)誤,也并不總是很明顯錯(cuò)誤是從哪里引發(fā)的。
我們都見過(guò)長(zhǎng)長(zhǎng)的代碼塊包裝在一個(gè) try-catch 塊中。在這種情況下,catch 塊實(shí)際上充當(dāng) goto 語(yǔ)句,這通常被認(rèn)為是有害的(奇怪的是,C 中的關(guān)鍵字被認(rèn)為可以接受的少數(shù)用例之一是錯(cuò)誤后清理,因?yàn)樵撜Z(yǔ)言沒(méi)有 Golang- 樣式延遲語(yǔ)句)。
如果你確實(shí)從源頭捕獲異常,你會(huì)得到一個(gè)不太優(yōu)雅的 Go 錯(cuò)誤模式版本。這可能會(huì)解決混淆代碼的問(wèn)題,但會(huì)遇到另一個(gè)問(wèn)題:性能。在諸如 Java 之類的語(yǔ)言中,拋出異常可能比函數(shù)的常規(guī)返回慢數(shù)百倍。
Java 中最大的性能成本是由打印異常的堆棧跟蹤造成的,這是昂貴的,因?yàn)檫\(yùn)行的程序必須檢查編譯它的源代碼 。僅僅進(jìn)入一個(gè) try 塊也不是空閑的,因?yàn)樾枰4?CPU 內(nèi)存寄存器的先前狀態(tài),因?yàn)樗鼈兛赡苄枰趻伋霎惓5那闆r下恢復(fù)。
如果您將異常視為通常不會(huì)發(fā)生的異常情況,那么異常的缺點(diǎn)并不重要。這可能是傳統(tǒng)的單體應(yīng)用程序的情況,其中大部分代碼庫(kù)不必進(jìn)行網(wǎng)絡(luò)調(diào)用——一個(gè)操作格式良好的數(shù)據(jù)的函數(shù)不太可能遇到錯(cuò)誤(除了錯(cuò)誤的情況)。一旦您在代碼中添加 I/O,無(wú)錯(cuò)誤代碼的夢(mèng)想就會(huì)破滅:您可以忽略錯(cuò)誤,但不能假裝它們不存在!
try {
doSometing()
} catch (IOException e) {
// ignore it
}
與大多數(shù)其他編程語(yǔ)言不同,Golang 接受錯(cuò)誤是不可避免的。 如果在單體架構(gòu)時(shí)代還不是這樣,那么在今天的模塊化后端服務(wù)中,服務(wù)通常和外部 API 調(diào)用、數(shù)據(jù)庫(kù)讀取和寫入以及與其他服務(wù)通信 。
以上所有方法都可能失敗,解析或驗(yàn)證從它們接收到的數(shù)據(jù)(通常在無(wú)模式 JSON 中)也可能失敗。Golang 使可以從這些調(diào)用返回的錯(cuò)誤顯式化,與普通返回值的等級(jí)相同。從函數(shù)調(diào)用返回多個(gè)值的能力支持這一點(diǎn),這在大多數(shù)語(yǔ)言中通常是不可能的。Golang 的錯(cuò)誤處理系統(tǒng)不僅僅是一種語(yǔ)言怪癖,它是一種將錯(cuò)誤視為替代返回值的完全不同的方式!
重復(fù) if err != nil
對(duì) Go 錯(cuò)誤處理的一個(gè)常見批評(píng)是被迫重復(fù)以下代碼塊:
res, err := doSomething()
if err != nil {
// Handle error
}
對(duì)于新用戶來(lái)說(shuō),這可能會(huì)覺(jué)得沒(méi)用而且浪費(fèi)行數(shù):在其他語(yǔ)言中需要 3 行的函數(shù)很可能會(huì)增長(zhǎng)到 12 行 :
這么多行代碼!這么低效!如果您認(rèn)為上述內(nèi)容不優(yōu)雅或浪費(fèi)代碼,您可能忽略了我們檢查代碼中的錯(cuò)誤的全部原因:我們需要能夠以不同的方式處理它們!對(duì) API 或數(shù)據(jù)庫(kù)的調(diào)用可能會(huì)被重試。
有時(shí)事件的順序很重要:調(diào)用外部 API 之前發(fā)生的錯(cuò)誤可能不是什么大問(wèn)題(因?yàn)閿?shù)據(jù)從未通過(guò)發(fā)送),而 API 調(diào)用和寫入本地?cái)?shù)據(jù)庫(kù)之間的錯(cuò)誤可能需要立即注意,因?yàn)?這可能意味著系統(tǒng)最終處于不一致的狀態(tài)。即使我們只想將錯(cuò)誤傳播給調(diào)用者,我們也可能希望用失敗的解釋來(lái)包裝它們,或者為每個(gè)錯(cuò)誤返回一個(gè)自定義錯(cuò)誤類型。
并非所有錯(cuò)誤都是相同的,并且向調(diào)用者返回適當(dāng)?shù)腻e(cuò)誤是 API 設(shè)計(jì)的重要部分,無(wú)論是對(duì)于內(nèi)部包還是 REST API 。
不必?fù)?dān)心在你的代碼中重復(fù) if err != nil ——這就是 Go 中的代碼應(yīng)該看起來(lái)的樣子。
自定義錯(cuò)誤類型和錯(cuò)誤包裝
從導(dǎo)出的方法返回錯(cuò)誤時(shí),請(qǐng)考慮指定自定義錯(cuò)誤類型,而不是單獨(dú)使用錯(cuò)誤字符串。字符串在意外代碼中是可以的,但在導(dǎo)出的函數(shù)中,它們成為函數(shù)公共 API 的一部分。更改錯(cuò)誤字符串將是一項(xiàng)重大更改——如果沒(méi)有明確的錯(cuò)誤類型,需要檢查返回錯(cuò)誤類型的單元測(cè)試將不得不依賴原始字符串值!事實(shí)上,基于字符串的錯(cuò)誤也使得在私有方法中測(cè)試不同的錯(cuò)誤案例變得困難,因此您也應(yīng)該考慮在包中使用它們。回到錯(cuò)誤與異常的爭(zhēng)論,返回錯(cuò)誤也使代碼比拋出異常更容易測(cè)試,因?yàn)殄e(cuò)誤只是要檢查的返回值。不需要測(cè)試框架或在測(cè)試中捕獲異常 。
可以在 database/sql 包中找到簡(jiǎn)單自定義錯(cuò)誤類型的一個(gè)很好的示例。它定義了一個(gè)導(dǎo)出常量列表,表示包可以返回的錯(cuò)誤類型,最著名的是 sql.ErrNoRows。雖然從 API 設(shè)計(jì)的角度來(lái)看,這種特定的錯(cuò)誤類型有點(diǎn)問(wèn)題(您可能會(huì)爭(zhēng)辯說(shuō) API 應(yīng)該返回一個(gè)空結(jié)構(gòu)而不是錯(cuò)誤),但任何需要檢查空行的應(yīng)用程序都可以導(dǎo)入該常量并在代碼中使用它不必?fù)?dān)心錯(cuò)誤消息本身會(huì)改變和破壞代碼。
對(duì)于更復(fù)雜的錯(cuò)誤處理,您可以通過(guò)實(shí)現(xiàn)返回錯(cuò)誤字符串的 Error() 方法來(lái)定義自定義錯(cuò)誤類型。自定義錯(cuò)誤可以包括元數(shù)據(jù),例如錯(cuò)誤代碼或原始請(qǐng)求參數(shù)。如果您想表示錯(cuò)誤類別,它們很有用。DigitalOcean 的本教程展示了如何使用自定義錯(cuò)誤類型來(lái)表示可以重試的一類臨時(shí)錯(cuò)誤。
通常,錯(cuò)誤會(huì)通過(guò)將低級(jí)錯(cuò)誤與更高級(jí)別的解釋包裝起來(lái),從而在程序的調(diào)用堆棧中傳播。例如,數(shù)據(jù)庫(kù)錯(cuò)誤可能會(huì)以下列格式記錄在 API 調(diào)用處理程序中:調(diào)用 CreateUser 端點(diǎn)時(shí)出錯(cuò):查詢數(shù)據(jù)庫(kù)時(shí)出錯(cuò):pq:檢測(cè)到死鎖。這很有用,因?yàn)樗梢詭椭覀兏欏e(cuò)誤在系統(tǒng)中傳播的過(guò)程,向我們展示根本原因(數(shù)據(jù)庫(kù)事務(wù)引擎中的死鎖)以及它對(duì)更廣泛系統(tǒng)的影響(調(diào)用者無(wú)法創(chuàng)建新用戶)。
自 Go 1.13 以來(lái),此模式具有特殊的語(yǔ)言支持,并帶有錯(cuò)誤包裝。通過(guò)在創(chuàng)建字符串錯(cuò)誤時(shí)使用 %w 動(dòng)詞,可以使用 Unwrap() 方法訪問(wèn)底層錯(cuò)誤。除了比較錯(cuò)誤相等性的函數(shù) errors.Is() 和 errors.As() 外,程序還可以獲取包裝錯(cuò)誤的原始類型或標(biāo)識(shí)。這在某些情況下可能很有用,盡管我認(rèn)為在確定如何處理所述錯(cuò)誤時(shí)最好使用頂級(jí)錯(cuò)誤的類型。
Panics
不要 panic()!長(zhǎng)時(shí)間運(yùn)行的應(yīng)用程序應(yīng)該優(yōu)雅地處理錯(cuò)誤而不是panic。即使在無(wú)法恢復(fù)的情況下(例如在啟動(dòng)時(shí)驗(yàn)證配置),最好記錄一個(gè)錯(cuò)誤并優(yōu)雅地退出。panic比錯(cuò)誤消息更難診斷,并且可能會(huì)跳過(guò)被推遲的重要關(guān)閉代碼。
Logging
我還想簡(jiǎn)要介紹一下日志記錄,因?yàn)樗翘幚礤e(cuò)誤的關(guān)鍵部分。通常你能做的最好的事情就是記錄收到的錯(cuò)誤并繼續(xù)下一個(gè)請(qǐng)求。
除非您正在構(gòu)建簡(jiǎn)單的命令行工具或個(gè)人項(xiàng)目,否則您的應(yīng)用程序應(yīng)該使用結(jié)構(gòu)化的日志庫(kù),該庫(kù)可以為日志添加時(shí)間戳,并提供對(duì)日志級(jí)別的控制。最后一部分特別重要,因?yàn)樗鼘⒃试S您突出顯示應(yīng)用程序記錄的所有錯(cuò)誤和警告。通過(guò)幫助將它們與信息級(jí)日志分開,這將為您節(jié)省無(wú)數(shù)時(shí)間。
微服務(wù)架構(gòu)還應(yīng)該在日志行中包含服務(wù)的名稱以及機(jī)器實(shí)例的名稱。默認(rèn)情況下記錄這些時(shí),程序代碼不必?fù)?dān)心包含它們。您也可以在日志的結(jié)構(gòu)化部分中記錄其他字段,例如收到的錯(cuò)誤(如果您不想將其嵌入日志消息本身)或有問(wèn)題的請(qǐng)求或響應(yīng)。只需確保您的日志沒(méi)有泄露任何敏感數(shù)據(jù),例如密碼、API 密鑰或用戶的個(gè)人數(shù)據(jù)!
對(duì)于日志庫(kù),我過(guò)去使用過(guò) logrus 和 zerolog,但您也可以選擇其他結(jié)構(gòu)化日志庫(kù)。如果您想了解更多信息,互聯(lián)網(wǎng)上有許多關(guān)于如何使用這些的指南。如果您將應(yīng)用程序部署到云中,您可能需要日志庫(kù)上的適配器來(lái)根據(jù)您的云平臺(tái)的日志 API 格式化日志 - 沒(méi)有它,云平臺(tái)可能無(wú)法檢測(cè)到日志級(jí)別等某些功能。
如果您在應(yīng)用程序中使用調(diào)試級(jí)別日志(默認(rèn)情況下通常不記錄),請(qǐng)確保您的應(yīng)用程序可以輕松更改日志級(jí)別,而無(wú)需更改代碼。更改日志級(jí)別還可以暫時(shí)使信息級(jí)別甚至警告級(jí)別的日志靜音,以防它們突然變得過(guò)于嘈雜并開始淹沒(méi)錯(cuò)誤。您可以使用在啟動(dòng)時(shí)檢查以設(shè)置日志級(jí)別的環(huán)境變量來(lái)實(shí)現(xiàn)這一點(diǎn)。
原文:
應(yīng)用程序發(fā)生異常 未知的軟件異常
1.病毒木馬造成的,在當(dāng)今互聯(lián)網(wǎng)時(shí)代,病毒坐著為了獲得更多的牟利,常用病毒綁架應(yīng)用程序和系統(tǒng)文件,然后某些安全殺毒軟件把被病毒木馬感染的應(yīng)用程序和系統(tǒng)文件當(dāng)病毒殺了導(dǎo)致的。
2.應(yīng)用程序組件丟失,應(yīng)用程序完整的運(yùn)行需要一些系統(tǒng)文件或者某些ll文件支持的,如果應(yīng)用程序組件不完整也會(huì)導(dǎo)致的。
3.系統(tǒng)文件損壞或丟失,盜版系統(tǒng)或Ghost版本系統(tǒng),很容易出現(xiàn)該問(wèn)題。
4.操作系統(tǒng)自身的問(wèn)題,操作系統(tǒng)本身也會(huì)有bug 。
5.硬件問(wèn)題,例如內(nèi)存條壞了或者存在質(zhì)量問(wèn)題,或者內(nèi)存條的金手指的灰塵特別多。
應(yīng)用程序發(fā)生異常怎么辦
1.檢查電腦是否存在病毒,請(qǐng)使用百度衛(wèi)士進(jìn)行木馬查殺。
2.系統(tǒng)文件損壞或丟失,盜版系統(tǒng)或Ghost版本系統(tǒng),很容易出現(xiàn)該問(wèn)題。建議:使用完整版或正版系統(tǒng)。
3.安裝的軟件與系統(tǒng)或其它軟件發(fā)生沖突,找到發(fā)生沖突的軟件,卸載它。如果更新下載補(bǔ)丁不是該軟件的錯(cuò)誤補(bǔ)丁,也會(huì)引起軟件異常,解決辦法:卸載該軟件,重新下載重新安裝試試。順便檢查開機(jī)啟動(dòng)項(xiàng),把沒(méi)必要啟動(dòng)的啟動(dòng)項(xiàng)禁止開機(jī)啟動(dòng)。
4.如果檢查上面的都沒(méi)問(wèn)題,可以試試下面的方法。
打開開始菜單→運(yùn)行→輸入cmd→回車,在命令提示符下輸入下面命令 for %1 in (%windir%\system32\*.dll) do regsvr32.exe /s %1回車。
完成后,在輸入下面
for %i in (%windir%\system32\*.ocx) do regsvr32.exe /s %i 回車。
如果怕輸入錯(cuò)誤,可以復(fù)制這兩條指令,然后在命令提示符后擊鼠標(biāo)右鍵,打“粘貼”,回車,耐心等待,直到屏幕滾動(dòng)停止為止。(重啟電腦)。
只是Go里面的Error Check比較不直觀而已,其實(shí)可以封裝一層讓它更好看的。比如Rust的ResultT, E,它包含了一個(gè)Ok(..)和Err(..),Ok表示正確,然后帶有正確的返回值,而Err則表示錯(cuò)誤,然后帶著錯(cuò)誤信息。這樣處理起來(lái)就比較好看了,你可以選擇忽略它,讓程序直接在出錯(cuò)的地方掛掉,像這樣someFunctionMayFail().unwrap(); // 要是出錯(cuò)了,就直接掛掉
或者在掛掉的時(shí)候,帶一個(gè)自己的出錯(cuò)信息someFunctionMayFail().ok().expect("Expecting a xxxxx");
或者自己處理let return_val = match someFunctionMayFail() {
Ok(v) = v,
Err(err) = {
// Deal with the error
// for example:
// fail!("Fail!!!! {}", err);
}
};
當(dāng)然,我不是說(shuō)它和Go的那個(gè)Error Check有什么本質(zhì)的區(qū)別,反正都是處理錯(cuò)誤,但是我個(gè)人覺(jué)得Rust這樣寫更舒服。
當(dāng)一個(gè)函數(shù)調(diào)用返回一個(gè)錯(cuò)誤時(shí),調(diào)用者應(yīng)當(dāng)負(fù)責(zé)檢查錯(cuò)誤并采取合適的處理應(yīng)對(duì)。根據(jù)情形,將有許多可能的處理場(chǎng)景。接下來(lái)我們看 5 個(gè)策略:
Go 語(yǔ)言的錯(cuò)誤處理有特定的規(guī)律。進(jìn)行錯(cuò)誤檢查之后,檢測(cè)到失敗的情況往往都在成功之前。如果檢測(cè)到的失敗導(dǎo)致函數(shù)返回,成功的邏輯一般不會(huì)放在 else 塊中而是在外層的作用域中。函數(shù)會(huì)有一種通常的形式,就是在開頭有一連串的檢查來(lái)返回錯(cuò)誤,之后跟著實(shí)際的函數(shù)體一直到最后。
使用文件名作為輸入
另一個(gè)常見錯(cuò)誤是將文件名傳遞給函數(shù)。
假設(shè)我們必須實(shí)現(xiàn)一個(gè)函數(shù)來(lái)計(jì)算文件中的空行數(shù)。最自然的實(shí)現(xiàn)是這樣的:
filename 作為輸入給出,所以我們打開它然后我們實(shí)現(xiàn)我們的邏輯,對(duì)吧?
現(xiàn)在,假設(shè)我們希望在此函數(shù)之上實(shí)現(xiàn) 單元測(cè)試 ,以使用普通文件,空文件,具有不同編碼類型的文件等進(jìn)行測(cè)試。很容易變得非常難以管理。
此外,如果我們想要實(shí)現(xiàn)相同的邏輯但是對(duì)于HTTP主體,例如,我們將不得不為此創(chuàng)建另一個(gè)函數(shù)。
Go有兩個(gè)很棒的抽象: io.Reader 和 io.Writer 。相反,通過(guò)一個(gè)文件名,我們可以簡(jiǎn)單地傳遞一個(gè) io.Reader 作為 抽象 的數(shù)據(jù)源。
它是文件嗎?一個(gè)HTTP正文?字節(jié)緩沖區(qū)?這并不重要,因?yàn)槲覀內(nèi)匀粫?huì)使用相同的 Read 方法。
在我們的例子中,我們甚至可以緩沖輸入以逐行讀取它。所以,我們可以使用 bufio.Reader 它的 ReadLine 方法:
現(xiàn)在,打開文件本身的責(zé)任委托給 count 客戶:
使用第二種實(shí)現(xiàn),無(wú)論 實(shí)際數(shù)據(jù)源 如何,都可以調(diào)用該函數(shù)。同時(shí),它將 促進(jìn) 我們的單元測(cè)試,因?yàn)槲覀兛梢院?jiǎn)單地創(chuàng)建一個(gè) bufio.Reader 來(lái)自 string :
翻譯自:
go語(yǔ)言調(diào)取包會(huì)先找vendor下的包 ,這個(gè)錯(cuò)說(shuō)明vendor下有sirupsen這個(gè)包
github.com/Sirupsen/logrus" and "github.com/sirupsen/logrus,
直接把Sirupsen換為sirupsen就可以使用了