引言
在Golang與其他web服務(包括髮送和接收)的接口調試,一直是一個痛點。將所有的值都放入fmt也挺麻煩的。
故障排除時,傻瓜式地fmt.Printf(" %+v ", req),輸出內容慘不忍睹。
為了簡化操作,有必要寫個函數,隨處可用,於是有了下面的代碼。
正文
直接上代碼:
<code>func formatRequest(r *http.Request) string { var request []string url := fmt.Sprintf(“%v %v %v”, r.Method, r.URL, r.Proto) request = append(request, url) request = append(request, fmt.Sprintf(“Host: %v”, r.Host)) for name, headers := range r.Header { name = strings.ToLower(name) for _, h := range headers { request = append(request, fmt.Sprintf(“%v: %v”, name, h)) } } // 處理POST請求體 if r.Method == “POST” { r.ParseForm() request = append(request, “\n”) request = append(request, r.Form.Encode()) } return strings.Join(request, “\n”) }/<code>
輸出結果看起來時這樣的
<code>POST https://blabla.example.com/o/oauth2/token HTTP/1.1 Host: blabla.example.com content-type: application/x-www-form-urlencoded client_id=ssssss&client_secret=sssss&grant_type=authorization_code&redirect_uri=ssssss&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile/<code>
一個小問題是,如果讀一個外部請求的 r.Body,只能去緩衝區。這意味著,請求有可能失敗,因為發送的 Content-Length 頭將設置為請求的原始長度。造成請求體的實際長度為0。
為了解決這個問題,可以把正文讀入緩衝區,然後打印出請求後再寫回來:
<code>// 緩存請求體 bodyBuffer, _ := ioutil.ReadAll(r.Body) req.Body = myReader{bytes.NewBuffer(buf)} fmt.Printf("--> %s\n\n", formatRequest(req)) req.Body = myReader{bytes.NewBuffer(buf)}/<code>
輪子已經好了
無可避免,還是搜索的不夠徹底,這個需求的輪子早就造好,放在golang裡了。
httputil包有一個預先準備好的DumpRequest方法。輸出幾乎完全一樣,這太讚的,因為它少了對第三方代碼的依賴。
結果就是2行搞定,還有2行是錯誤處理。
<code>requestDump, err := httputil.DumpRequest(req, true) if err != nil { fmt.Println(err) } fmt.Println(string(requestDump))/<code>
req參數是http, true讓函數知道是否存在請求體。
寫在最後
大神都已經造好輪子了,我們只用找出來裝上用就行了。
Happy coding :)