標籤 golang 下的所有文章

Go http 的幾種錯誤

之前遇到了很多 timeout,但是仔細看錯誤提示好像不完全一樣,於是就做了個簡單的試驗:

Client 上看到的錯誤

找不到服務器(no such host)的幾種情況:

# 域名不存在,瞄了下代碼,應該是 dns 包返回的
Get http://a.b/abc: dial tcp: lookup a.b: no such host

# ip 不合法不會直接檢查,也會返回同樣錯誤
Get http://127.0.0.1888:8080/abc: dial tcp: lookup 127.0.0.1888: no such host

# 端口瞎填會直接報錯,都不會發請求
Get http://127.0.0.1:65536/abc: dial tcp: address 65536: invalid port


拒絕連接,對方端口未監聽、進程掛掉等等

Get http://127.0.0.1:8080/abc: dial tcp 127.0.0.1:8080: connect: connection refused


建立連接超時

Get http://127.0.0:8080/abc: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)


等待返回 header, 一般是接口還在處理邏輯,沒有返回任何數據;或者對方只是個普通的 tcp 服務,但不是 http

Get http://127.0.0.1:8080/abc: net/http: request canceled (Client.Timeout exceeded while awaiting headers)


客戶端讀取超時:已建立好連接,已經開始返回數據,但是body 太大太慢:

wait_test.go:48: net/http: request canceled (Client.Timeout exceeded while reading body)


Server 上看到的錯誤

客戶端主動斷開連接,服務器端在調用 Write(p []byte) (n int, err error) 時會返回:

wait_test.go:21: write tcp 127.0.0.1:8080->127.0.0.1:49290: write: broken pipe


客戶端主動斷開連接,通常會直接使用 ctx.Done() 檢測到,這個時候 ctx.Err() 裡會拿到這個信息:

context canceled

參考連結

https://romatic.net/post/go_net_errors/

https://colobu.com/2016/07/01/the-complete-guide-to-golang-net-http-timeouts/

Sublime Text 開發 Golang 環境配置

Sublime Text Package 安裝

GoSublime

在margo.go 註解改用LSP gopls
 
 // &golang.Gocode{
 // // Whether or not to do gocode completion using source code
 // // instead of the pre-compiled package files.
 // // Using source is often slower but offer more up-to-date completions.
 // Source: true,

 // // show the function parameters. this can take up a lot of space
 // ShowFuncParams: true,

 // // whether or not to include Test*, Benchmark* and Example* functions in the auto-completion list
 // // gs: this replaces the `autocomplete_tests` setting
 // ProposeTests: false,

 // // whether or not builtin types and functions should be shown in the auto-completion list
 // // gs: this replaces the `autocomplete_builtins` setting
 // ProposeBuiltins: true,
 // },


 golangci-lint 啟用這些檢查

 &golang.Linter{Name: "golangci-lint", Args: []string{
 "run",

 // 2019/10/29增加
 "--enable=interfacer",
 "--enable=nakedret",
 "--enable=goconst",

 "--enable=bodyclose",
 "--enable=gocritic",
 "--enable=prealloc",
 "--enable=unconvert",
 "--enable=whitespace",
 "--enable=wsl",

 "--disable=deadcode",
 "--max-same-issues=0",
 "--fast",
 }},
LSP (gopls)

配置設定
{
    "auto_show_diagnostics_panel": "never",
    "show_diagnostics_in_view_status": false,
    "log_server": false,
	"clients":
	{
		"gopls":
		{
			"enabled": true
		}
	}
}

還需要特別安裝
LSP-gopls套件

=============2024/05/29更新======================
Gosublime停止更新,不支援sublime text 4
只需要安裝LSP套件

// Settings in here override those in "LSP/LSP.sublime-settings"
{
    "show_diagnostics_in_view_status": false,
    "clients":
    {
        "gopls":
        {
            "enabled": true
        }
    },
    "lsp_format_on_save": true,
    "lsp_code_actions_on_save": {
        "source.fixAll": false, // 自動修復所有錯誤
        "source.organizeImports": true // 自動新增排序import套件
    }
}

 

有效地去 – Effective go 正體中文翻譯

簡介

Go 是一門新的程式語言。雖然它從現有的程式語言中借鏡了許多設計理念,但它也有許多與眾不同的特性。若你把用 C++ / Java 撰寫的程式改寫成等價的 Go 程式,恐怕難以得到令人滿意的結果。同樣地,用 Go 語言的角度來解決問題,你可能會寫出有效但不太一樣的程式。換句話說,想要寫出好的 Go 程式,對於 Go 語言特性及慣例的掌握是重要的一環。同時,對於社群慣例 (比如排版、命名方式、程式的建立等等) 也應該要適當的瞭解,這樣其他使用 Go 語言的開發者才容易理解你寫的程式。

這份文件列舉出一些訣竅,讓你寫出清楚、符合 Go 語言特性的程式。這是對於 Go 語言規格書導覽 Go 語言以及 如何撰寫 Go 程式 等三份文件的補充,所以你應該先讀過這三份文件。
繼續閱讀

GoLang Cookie

GoLang Cookie


Go 語言內 struct methods 該使用 pointer 或 value 傳值?

寫入或讀取

如果您需要對 Struct 內的成員進行修改,那請務必使用 Pointer 傳值,相反的,Go 會使用 Copy struct 方式來傳入,但是用此方式你就拿不到修改後的資料。

效能

假設 Struct 內部成員非常的多,請務必使用 Pointer 方式傳入,這樣省下的系統資源肯定比 Copy Value 的方式還來的多。

一致性

在開發團隊內,如果有人使用 Pointer 有人使用 Value 方式,這樣寫法不統一,造成維護效率非常低,所以官方建議,全部使用 Pointer 方式是最好的寫法。

參考網站


Function types

從golang的官方文檔得知function types的解釋是這樣的。

A function type denotes the set of all functions with the same parameter and result types.

先找個例子來看一下:

package main

import "fmt"

// Greeting function types
type Greeting func(name string) string

func say(g Greeting, n string) {
    fmt.Println(g(n))
}

func english(name string) string {
    return "Hello, " + name
}

func main() {
    say(english, "World")
}

輸出

Hello, World

say()函數要求傳入一個Greeting類型,因為english函數的參數和返回值跟Greeting一樣,參考接口的概念這裡可以做類型轉換。我們換個方式來實現上面的功能:

package main

import "fmt"

// Greeting function types
type Greeting func(name string) string

func (g Greeting) say(n string) {
    fmt.Println(g(n))
}

func english(name string) string {
    return "Hello, " + name
}

func main() {
    g := Greeting(english)
    g.say("World")
}

同樣輸出Hello, World,只是給Greeting類型添加了say()方法。上面說了,函數類型是表示所有包含相同參數和返回類型的函數集合。我們在一開始先把func(name string) string這樣的函數聲明成Greeting類型,接著我們通過Greeting(english)將english函數轉換成Greeting類型。通過這個轉換以後,我們就可以借由變量g調用Greeting類型的say()方法。兩段代碼的差異就是go的類型系統添加方法和類C++語言添加類型方法的差異

既然是函數集合,那麼只有一個函數顯然是不足以說明問題的。

package main

import "fmt"

// Greeting function types
type Greeting func(name string) string

func (g Greeting) say(n string) {
    fmt.Println(g(n))
}

func english(name string) string {
    return "Hello, " + name
}

func french(name string) string {
    return "Bonjour, " + name
}

func main() {
    g := Greeting(english)
    g.say("World")
    g = Greeting(french)
    g.say("World")
}

輸出

Hello, World
Bonjour, World

在其他語言裡面,有些函數可以直接作為參數傳遞,有些是以函數指針進行傳遞,但是都沒有辦法像go這樣可以給函數類型「增加」新方法。

回到Go: net/http的HandlerFunc類型,只要Martini的函數遵循文檔中type HandlerFunc func(ResponseWriter, *Request)的要求,就可以轉換成HandlerFunc類型,也就可以調用func (HandlerFunc)ServeHTTP函數。

參考網站