Cookies management by TermsFeed Cookie Consent

๐Ÿœ Print HTTP request/response for debugging in Go

http

When writing an HTTP server or client in Go, it is often useful to print the full HTTP request or response to the standard output for debugging purposes. Using fmt.Println() may not be sufficient in this case because the output is not formatted and difficult to read. The better idea is to use the httputil.DumpRequest(), httputil.DumpRequestOut() and httputil.DumpResponse() functions which were created to pretty-print the HTTP request and response. Such pretty-printing or dumping means that the request/response is presented in a similar format as it is sent to and received from the server.

The rules for using these functions are simple:

Log client requests and responses

Check the example below to learn how to dump the HTTP client request and response using the httputil.DumpRequestOut() and httputil.DumpResponse() functions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
)

const serverAddr = "http://example.com/"

func main() {
    req, err := http.NewRequest(http.MethodGet, serverAddr, nil)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Add("test-header", "test-header-value")

    reqDump, err := httputil.DumpRequestOut(req, true)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("REQUEST:\n%s", string(reqDump))

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }

    respDump, err := httputil.DumpResponse(resp, true)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("RESPONSE:\n%s", string(respDump))
}

Output:

REQUEST:
GET / HTTP/1.1
Host: example.com
User-Agent: Go-http-client/1.1
Test-Header: test-header-value
Accept-Encoding: gzip

RESPONSE:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 357425
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Fri, 25 Feb 2022 06:48:03 GMT
Etag: "3147526947+gzip"
Expires: Fri, 04 Mar 2022 06:48:03 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECS (bsa/EB18)
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>
    <title>Example Domain</title>

    <meta charset="utf-8" />
    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style type="text/css">
...

Log requests on the server side

From the example below, you can find out how to pretty-print an incoming server request using the httputil.DumpRequest() function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
)

const port = 8080

func indexHandler(w http.ResponseWriter, r *http.Request) {
    reqDump, err := httputil.DumpRequest(r, true)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("REQUEST:\n%s", string(reqDump))
    w.Write([]byte("Hello World"))
}

func main() {
    http.HandleFunc("/", indexHandler)
    log.Printf("Starting HTTP server at port: %d\n", port)
    log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil))
}

Output:

2022/02/25 07:03:20 Starting HTTP server at port: 8080
REQUEST:
GET / HTTP/1.1
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Dnt: 1
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36

REQUEST:
GET /favicon.ico HTTP/1.1
Host: localhost:8080
Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,en-US;q=0.8,en;q=0.7
Connection: keep-alive
Dnt: 1
Referer: http://localhost:8080/
Sec-Ch-Ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36

Thank you for being on our site ๐Ÿ˜Š. If you like our tutorials and examples, please consider supporting us with a cup of coffee and we'll turn it into more great Go examples.

Have a great day!

Buy Me A Coffee

โฑ๏ธ Set HTTP client timeout in Go

Learn how to set a time limit for the execution of an HTTP request
http

โฐ Handle HTTP timeout error in Go

shorts http

๐Ÿงช Write end-to-end tests in Go using httptest.Server

shorts httptest http testing