Skip to content

Go http Package ​

Before You Start

  • Applies to: Go 1.21+ (examples verified with Go 1.22) · Prerequisites: Advanced: Concurrency · Read time: about 15 min

The net/http package in Go language standard library is excellent, providing a very complete implementation of HTTP clients and servers. You can build a very simple HTTP server with just a few lines of code.

Almost all web frameworks in Go are built on top of the existing http package with encapsulation and modifications. Therefore, it is highly recommended to master the http package before learning other frameworks.

Get Example ​

This article will not elaborate on HTTP-related knowledge. If you want to learn more, you can search on Baidu.

go
func main() {
  resp, err := http.Get("https://baidu.com")
  if err != nil {
    fmt.Println(err)
    return
  }
  defer resp.Body.Close()
  content, err := io.ReadAll(resp.Body)
  fmt.Println(string(content))
}

You can make simple requests by directly calling functions under the Http package. It will return a pointer and an error. After calling, you must manually close it.

Post Example ​

go
func main() {
   person := Person{
      UserId:   "120",
      Username: "jack",
      Age:      18,
      Address:  "usa",
   }

   json, _ := json.Marshal(person)
   reader := bytes.NewReader(json)

   resp, err := http.Post("https://golang.org", "application/json;charset=utf-8", reader)
   if err != nil {
      fmt.Println(err)
   }
   defer resp.Body.Close()
}

Client ​

Generally, we don't use the above methods directly, but configure a client ourselves to achieve more detailed requirements. This will use the http.Client{} struct. There are four configurable options in total:

  • Transport: Configure HTTP client data transmission related settings. If not provided, default strategy is used.
  • Timeout: Request timeout configuration
  • Jar: Cookie related configuration
  • CheckRedirect: Redirect configuration

Simple Example ​

go
func main() {
  client := &http.Client{}
  request, _ := http.NewRequest("GET", "https://golang.org", nil)
  resp, _ := client.Do(request)
  defer resp.Body.Close()
}

Add Header ​

go
func main() {
   client := &http.Client{}
   request, _ := http.NewRequest("GET", "https://golang.org", nil)
   request.Header.Add("Authorization","123456")
   resp, _ := client.Do(request)
   defer resp.Body.Close()
}

Some detailed configurations will not be elaborated here. Please learn on your own.

Server ​

For Go, creating an HTTP server only requires one line of code.

The first parameter is the listening address, and the second parameter is the handler. If it is empty, the default handler is used. In most cases, using the default handler DefaultServeMux is sufficient.

go
http.ListenAndServe("localhost:8080", nil)

Customization ​

Of course, you can also customize a server configuration:

go
func main() {
   server := &http.Server{
      Addr:              ":8080",
      Handler:           nil,
      TLSConfig:         nil,
      ReadTimeout:       0,
      ReadHeaderTimeout: 0,
      WriteTimeout:      0,
      IdleTimeout:       0,
      MaxHeaderBytes:    0,
      TLSNextProto:      nil,
      ConnState:         nil,
      ErrorLog:          nil,
      BaseContext:       nil,
      ConnContext:       nil,
   }
   server.ListenAndServe()
}

Please learn about some detailed configurations on your own.

Routing ​

First, you need to customize a struct to implement the ServeHTTP(ResponseWriter, *Request) method in the Handler interface, and then call the http.Handle() function:

go
func main() {
   http.Handle("/index", &MyHandler{})
   http.ListenAndServe(":8080", nil)
}

type MyHandler struct {
}

func (h *MyHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
   fmt.Println("my implement")
}

However, having to customize a struct every time is very cumbersome. You can also directly use the http.HandleFunc function. We only need to write the handler function, thus avoiding the need to create a struct. Internally, it uses the adapter type HandlerFunc. HandlerFunc type is an adapter that allows ordinary functions to be used as HTTP handlers. If f is a function with an appropriate signature, HandlerFunc(f) is a Handler that calls f.

go
func main() {
   http.HandleFunc("/index", func(responseWriter http.ResponseWriter, request *http.Request) {
      fmt.Println(responseWriter, "index")
   })
   http.ListenAndServe(":8080", nil)
}

ServerMux is the core struct that implements basic methods. DefaultServeMux is the default instance.

Reverse Proxy ​

The http package provides out-of-the-box reverse proxy functionality:

go
func main() {
   http.HandleFunc("/forward", func(writer http.ResponseWriter, request *http.Request) {
      director := func(request *http.Request) {
         request.URL.Scheme = "https"
         request.URL.Host = "golang.org"
         request.URL.Path = "index"
      }

      proxy := httputil.ReverseProxy{Director: director}
      proxy.ServeHTTP(writer, request)

   })

   http.ListenAndServe(":8080", nil)
}

The above code will forward all requests to https://golang.org/index.

Complete Example ​

The program below runs as-is: copy it into a file and execute go run main.go, or paste it into the Go Playground.

go
package main

import (
	"fmt"
	"io"
	"net/http"
	"net/http/httptest"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "path=%s", r.URL.Path)
	})

	srv := httptest.NewServer(handler)
	defer srv.Close()

	resp, err := http.Get(srv.URL + "/go")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(body))
}

Expected output:

text
200 path=/go

Common Pitfalls ​

  • http.Get has no timeout. Use &http.Client{Timeout: ...} for anything that talks to a real network.
  • Always close resp.Body. Leaking bodies prevents connection reuse and can exhaust sockets.
  • Servers need timeouts too. Set ReadTimeout, WriteTimeout and IdleTimeout on http.Server.
  • Reuse handlers, not servers. Wrap handlers with middleware (http.Handler) instead of duplicating logic.
  • httptest is for tests. In production, assemble a http.Server{Handler: mux} and run it with graceful shutdown.

Change Log ​

  • 2026-10-14: Added "Before You Start" notes, a complete runnable example with expected output, common pitfalls, and this change log.

Golang by www.golangdev.cn · Adapted in part from Golang 中文学习文档 (MIT, © 寒江蓑笠翁)