SoFunction
Updated on 2025-03-05

Detailed explanation of the use of net/http packages in Go language

The Http protocol (Hyper Text Transfer Protocol) is a simple request-response protocol that usually runs on TCP. The hypertext transmission protocol is the most widely used network transmission protocol on the Internet, and all WWW files must comply with this standard.

The Http protocol is based on client Cilent/server Server mode and is connected to the connection. Simply put, the client Cilent sends an http request Request to the server Server. After receiving the http service request Request, the server Server will return the requested data in the http response Response.

Built-in Go languagenet/httpThe package is very excellent and provides the implementation of HTTP client and server.

Official website address:/net/http

1. HTTP client

Make HTTP/HTTPS requests through Get, Head, Post, and PostForm functions.

resp, err := ("/")
resp, err := ("/upload", "image/jpeg", &buf)
resp, err := ("/form",{"key": {"Value"}, "id": {"123"}})

1.1 Send a Get request

Without request parameters:

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
)
func main() {
	resp, err := ("")
	if err != nil {
		("get failed, err:%v\n", err)
		return
	}
	// The program must close the body of the reply after using the response	defer ()
	body, err := ()
	if err != nil {
		("read from  failed, err:%v\n", err)
		return
	}
	(string(body))
}

With parameters, parameters need to be processed using net/url.

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)
func main() {
	apiUrl := "http://127.0.0.1:9090/get"
	// URL param
	data := {}
	("name", "mi")
	("age", "18")
	u, err := (apiUrl)
	if err != nil {
		("parse url requestUrl failed, err:%v\n", err)
	}
	// URL encode
	 = ()
	// http://127.0.0.1:9090/get?age=18&name=mi
	(())
	resp, err := (())
	if err != nil {
		("post failed, err:%v\n", err)
		return
	}
	defer ()
	b, err := ()
	if err != nil {
		("get resp failed, err:%v\n", err)
		return
	}
	// {"status": "ok"}
	(string(b))
}

Processing on the corresponding server side:

package main
import (
	"fmt"
	"net/http"
)
func getHandler(w , r *) {
	defer ()
	data := ()
    // mi
	(("name"))
    // 18
	(("age"))
	answer := `{"status": "ok"}`
	([]byte(answer))
}
func main() {
	("/get", getHandler)
	err := (":9090", nil)
	if err != nil {
		("http server failed, err:%v\n", err)
		return
	}
}

Header header information:

package main
import (
	"fmt"
	"net/http"
	"net/http/httputil"
)
func main() {
	url := "http://127.0.0.1:9090/get"
	request, err := (, url, nil)
	if err != nil {
		panic(err)
	}
	("Authorization", "jhs8723sd2dshd2")
	("User-Agent", "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1")
	resp, err := (request)
	if err != nil {
		panic(err)
	}
	defer ()
	// // Get web page content	s, err := (resp, true)
	if err != nil {
		panic(err)
	}
	("%s", s)
}

1.2 Send a POST request

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)
func main() {
	url := "http://127.0.0.1:9090/post"
	// Form data	// contentType := "application/x-www-form-urlencoded"
	// data := "name=mi&age=18"
	// json
	contentType := "application/json"
	data := `{"name":"mi","age":18}`
	resp, err := (url, contentType, (data))
	if err != nil {
		("post failed, err:%v\n", err)
		return
	}
	defer ()
	b, err := ()
	if err != nil {
		("get resp failed, err:%v\n", err)
		return
	}
	// {"status": "ok"}
	(string(b))
}

Corresponding server side:

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
)
func postHandler(w , r *) {
	defer ()
	// 1. When the request type is application/x-www-form-urlencoded, parses form data	()
	// Print form data	// map[]
	()
	(("name"), ("age"))
	// 2. When the request type is application/json, data is read from	b, err := ()
	if err != nil {
		("read  failed, err:%v\n", err)
		return
	}
	// {"name":"mi","age":18}
	(string(b))
	answer := `{"status": "ok"}`
	([]byte(answer))
}
func main() {
	("/post", postHandler)
	err := (":9090", nil)
	if err != nil {
		("http server failed, err:%v\n", err)
		return
	}
}

1.3 PostForm method

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
)
func main() {
	resp, err := ("http://127.0.0.1:9090/post",
		{"key": {"Value"}, "id": {"123"}})
	if err != nil {
		(err)
	}
	defer ()
	body, err := ()
	if err != nil {
		(err)
	}
	(string(body))
}

json:

package main
import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)
func main() {
	data := make(map[string]interface{})
	data["site"] = ""
	data["name"] = "tom"
	bytesData, _ := (data)
	resp, _ := ("/post", "application/json", (bytesData))
	body, _ := ()
	(string(body))
}

With headers parameters:

package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)
func main() {
	client := &{}
	req, err := ("POST", "http:///demo/", ("name=cjb"))
	if err != nil {
		(err)
	}
	("Content-Type", "application/x-www-form-urlencoded")
	("Cookie", "name=anny")
	resp, err := (req)
	defer ()
	body, err := ()
	if err != nil {
		(err)
	}
	(string(body))
}

1.4 Custom Client

To manage the header domain, redirect policies, and other settings of an HTTP client, create a Client:

package main
import (
	"fmt"
	"net/http"
	"net/http/httputil"
)
func main() {
	request, err := (, "", nil)
	if err != nil {
		panic(err)
	}
	client := {
		CheckRedirect: func(req *, via []*) error {
			("Redirect:", req)
			return nil
		},
	}
	("User-Agent", "User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1")
	resp, err := (request)
	if err != nil {
		panic(err)
	}
	defer ()
	s, err := (resp, true)
	("%s", s)
}

1.5 Custom Transport

To manage proxy, TLS configuration, keep-alive, compression, and other settings, create a Transport:

package main
import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/http"
)
// Use matching certificate methodfunc main() {
	// Contents of *.pem file	rootCA := ""
	roots := ()
	ok := ([]byte(rootCA))
	if !ok {
		panic("failed to parse root certificate")
	}
	client := &{
		Transport: &{
			TLSClientConfig:    &{RootCAs: roots},
			DisableCompression: true,
		},
	}
	resp, err := ("")
	if err != nil {
		panic(err)
	}
	defer ()
	body, err := ()
	if err != nil {
		panic(err)
	}
	if err != nil {
		("read from  failed, err:%v\n", err)
		return
	}
	(string(body))
}

Both Client and Transport types can be safely used by multiple goroutines at the same time. For efficiency considerations, it should be established at one time and reused as much as possible.

package main
import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"net/http"
)
// Skip the security checkfunc main() {
	tr := &{
		TLSClientConfig: &{InsecureSkipVerify: true},
	}
	client := &{Transport: tr}
	resp, err := ("https://localhost:8081")
	if err != nil {
		("error:", err)
		return
	}
	defer ()
	body, err := ()
	(string(body))
}

2. Server side

2.1 Default Server

ListenAndServe starts an HTTP server using the specified listening address and processor. The processor parameter is usually nil, which means that the packet variable is used.

DefaultServeMux as processor.

The Handle and HandleFunc functions can add processors to DefaultServeMux.

package main
import (
	"log"
	"net/http"
)
type httpServer struct {
}
func (server httpServer) ServeHTTP(w , r *) {
	([]byte())
}
func main() {
	var server httpServer
	("/foo", server)
	("/bar", func(w , r *) {
		([]byte())
	})
	((":9090", nil))
}

The Handler interface of the event handler is defined as follows:

type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

As long as this interface is implemented, you can implement your own handler processor.

If the first parameter address passed by ListenAndServe() is empty, the server uses it by default after startuphttp://127.0.0.1:8080Address for access.

If the second parameter passed in by this function is nil, the server will use the default multiplexer after startupDefaultServeMux

2.2 Default Server Example

Use the Go languagenet/httpPackage to write a simple server-side example that receives HTTP requests.net/http The package is for net package

Further encapsulation, specially used to process data from the HTTP protocol. The specific code is as follows:

package main
import (
	"fmt"
	"net/http"
)
func sayHello(w , r *) {
	(w, "Hello shanghai!")
}
func main() {
	("/", sayHello)
	err := (":9090", nil)
	if err != nil {
		("http server failed, err:%v\n", err)
		return
	}
}

After compiling the above code, execute it, open the browser on your computer and enter it in the address bar.127.0.0.1:9090Enter:

Output

Hello shanghai!

package main
import (
	"encoding/json"
	_ "encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
)
var (
	api   = "http://127.0.0.1:9090/"
	token = "9adf92861"
)
type Result struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}
type Resp struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
}
func wechatUrlHandle(w , r *) {
	// Get the link address	var wechatUrl string
	values := ()
	wechatUrl = ("url")
	// Verify the correctness of the URL	targetUrl, err := (wechatUrl)
	if err != nil {
		("parse url failed, err:%v\n", err)
	}
	(("url: %v", targetUrl))
	// Initiate a request for splicing parameters	data := ("token=%s&url=%s", token, ())
	headers := "application/x-www-form-urlencoded"
	res, err := (api, headers, (data))
	if err != nil {
		("post failed, err: %v\n", err)
		return
	}
	// Close the request resource	defer ()
	body, err := ()
	if err != nil {
		(w, ("get resp failed. err: %v\n", err))
		return
	}
	var info Result
	var ress Resp
	().Set("Content-Type", "application/json")
	if err := (body, &info); err == nil {
		(, )
		 = "200"
		 = "Success"
		t, _ := (ress)
		(t)
	} else {
		 = "200"
		 = "failure"
		t, _ := (ress)
		("err: ", err)
		(t)
	}
}
func main() {
	("/wechat/url", wechatUrlHandle)
	// Processor parameters are generally nil	err := (":9090", nil)
	if err != nil {
		("Http server failed. err: %v\n", err)
		return
	}
}

2.3 Custom Server

To manage server behavior, you can create a custom server.

Users can configure the server in more detail through the Server structure, including setting the address, setting the time exceeds the time for the requested read operation, etc.

package main
import (
	"log"
	"net/http"
	"time"
)
type httpServer struct {
}
func (server httpServer) ServeHTTP(w , r *) {
	([]byte())
}
func main() {
	s := &{
		Addr:           ":9090",
		Handler:        httpServer{},
		ReadTimeout:    10 * ,
		WriteTimeout:   10 * ,
		MaxHeaderBytes: 1 << 20,
	}
	(())
}

2.4 Multiplexer

The basic principle of multiplexer: find the corresponding processor based on the requested URL address and call the corresponding processor.ServeHTTP()Method handles the request.

DefaultServeMux is the default multiplexer for the net/http package, and it is actually an instance of ServeMux.

The HandleFunc() function is used to register a processor for the specified URL. The HandleFunc() processor function internally calls the HandleFunc method corresponding to the DefaultServeMux object.

2.4.1 ServeMux and DefaultServeMux

We can register multiple processors using the default multiplexer to achieve the same function as the processor.

The following shows how to create your own server with the default multiplexer.

package main
import (
	"fmt"
	"net/http"
)
//Define multiple processorstype handle1 struct{}
func (h1 *handle1) ServeHTTP(w , r *) {
	(w, "handle one")
}
type handle2 struct{}
func (h2 *handle2) ServeHTTP(w , r *) {
	(w, "handle two")
}
func main() {
	handle1 := handle1{}
	handle2 := handle2{}
	// Handler:nil indicates that the server uses the default multiplexer DefaultServeMux	s := &amp;{
		Addr:    "127.0.0.1:8080",
		Handler: nil,
	}
	// The Handle function calls the multiplexer method	("/handle1", &amp;handle1)
	("/handle2", &amp;handle2)
	()
}

We specify two processors by using our own handle1 and handle2. The () function can call the () method to handle the request.

Handle: nil The corresponding processor is DefaultServeMux.

In the ServeHTTP() method of the ServeMux object, find the server we registered according to the URL and then request it to handle.

Although the default multiplexer is very useful, it is still not recommended because it is a global variable and all code can modify it. Some third-party libraries may conflict with the default multiplexer. So the recommended way is customization.

2.4.2 Custom Multiplexer

package main
import (
	"fmt"
	"net/http"
)
func newservemux(w , r *) {
	(w, "NewServeMux")
}
func main() {
	mux := ()
	("/", newservemux)
	s := &{
		Addr:    ":8081",
		Handler: mux,
	}
	()
}

NewServeMux is essentially ServeMux.

2.4.3 Routing matching of ServeMux

We now need to bind three URLs: /, /happy, /bad.

package main
import (
	"fmt"
	"net/http"
)
func newservemux(w , r *) {
	(w, "NewServeMux")
}
func newservemuxhappy(w , r *) {
	(w, "Newservemuxhappy")
}
func newservemuxbad(w , r *) {
	(w, "NewServeMuxbad")
}
func main() {
	mux := ()
	("/", newservemux)
	("/happy", newservemuxhappy)
	("/bad", newservemuxbad)
	s := &{
		Addr:    ":8080",
		Handler: mux,
	}
	()
}

2.5 HttpRouter

One of the shortcomings of ServeMux is that it cannot use variables to implement URL pattern matching, while HttpRouter can, HttpRouter is a high-performance

The three-party HTTP routing packets make up for the insufficient routing problem in the net/http packets.

$ go get /julienschmidt/httprouter

To use httprouter, you must first use the New() function to generate a *Router routing object, and then use GET() to register a matching function

, and finally pass this parameter into the function to listen to the service.

package main
import (
	"net/http"
	"/julienschmidt/httprouter"
)
func Hello(w , r *, _ ) {
	([]byte("Hello,httprouter!"))
}
func main() {
	router := ()
	("/", Hello)
	(":8080", router)
}

More importantly, it provides two matching patterns for URLs:

  • /user/:pac: Accurate matching /user/pac
  • /user/*pac: Match all patterns /user/hello
Pattern: /user/:user
 /user/gordon              match
 /user/you                 match
 /user/gordon/profile      no match
 /user/                    no match
Pattern: /src/*filepath
 /src/                     match
 /src/          match
 /src/subdir/   match
package main
import (
	"fmt"
	"log"
	"net/http"
	"/julienschmidt/httprouter"
)
func Index(w , r *, _ ) {
	(w, "Welcome!\n")
}
func Hello(w , r *, ps ) {
	(w, "hello, %s!\n", ("name"))
}
func main() {
	router := ()
	("/", Index)
	("/hello/:name", Hello)
	((":8080", router))
}

Of course, there are details of the POST() and DELETE() functions here, so I won't introduce them one by one.

3. Other applications

3.1 DNS

package main
import (
	"fmt"
	"log"
	"net"
)
func main() {
	// Return to IP address according to domain name	addr, err := ("ip", "")
	if err != nil {
		return
	}
	// 2023/07/24 20:45:43 Corresponding address ip address----> 172.21.6.96	(" Corresponding address ip address---->", addr)
	// Find DNS A records	iprecords, _ := ("")
	for _, ip := range iprecords {
		// LookupIP -----&gt; 172.21.6.96
		("LookupIP -----&gt;", ip)
	}
	//Find DNS CNAME records	canme, _ := ("")
	// LookupCNAME -----&gt; .
	("LookupCNAME -----&gt;", canme)
	//Find DNS PTR records	ptr, e := ("172.21.6.96")
	if e != nil {
		// lookup 172.21.6.96: dnsquery: DNS name does not exist.
		(e)
	} else {
		(ptr)
	}
	for _, ptrval := range ptr {
		(ptrval)
	}
	//Find DNS NS records Name server records	nameserver, _ := ("")
	for _, ns := range nameserver {
		/*
			 ns record &{.}
			 ns record &{.}
			 ns record &{.}
			 ns record &{.}
			 ns record &{.}
		 */
		("ns record", ns)
	}
	//Find DNS MX records Mail server records	mxrecods, _ := ("")
	for _, mx := range mxrecods {
		("mx:", mx)
	}
	//Find the text information corresponding to the DNS TXT record	txtrecords, _ := ("")
	for _, txt := range txtrecords {
		/*
			txt: _globalsign-domain-verification=qjb28W2jJSrWj04NHpB0CvgK9tle5JkOq-EcyWBgnE
			txt: google-site-verification=GHb98-6msqyx_qqjGl5eRatD3QTHyVB6-xQ3gJB5UwM
			txt: v=spf1 include: include: include: include: mx ptr -all
		*/
		("txt:", txt)
	}
	// Check the local IP address	addrs, err := ()
	if err != nil {
		return
	}
	for _, address := range addrs {
		// Check the IP address to determine whether the loopback address is		if ipnet, ok := address.(*); ok &amp;&amp; !() {
			if .To4() != nil {
				/*
					 Local address --> 169.254.124.27
					 Local address --> 169.254.27.66
					 Local address --> 169.254.158.118
					 Local address --> 192.168.223.1
					 Local address --> 192.168.132.1
					 Local address --> 192.168.226.185
				 */
				("Local address -->", ())
			}
		}
	}
}

3.2 Simple tcp request implementation

3.2.1 Server

package main
import (
	"bufio"
	"io"
	"log"
	"net"
)
func pes(conn ) {
	defer ()
	read := (conn)
	for {
		var p [512]byte
		n, err := (p[:])
		if err != nil {
			if err ==  {
				("Client Close Link", ().String())
				return
			}
			("Read failed", ())
			return
		}
		("The client sends the message as", string(p[:n]))
		([]byte("ok"))
	}
}
func main() {
	lis, err := ("tcp", "127.0.0.1:20003")
	if err != nil {
		("listen ,err ", ())
		return
	}
	for {
		conn, err := ()
		if err != nil {
			("Create link exception", ())
		}
		go pes(conn)
	}
}

3.2.2 Client

package main
import (
	"bufio"
	"io"
	"log"
	"net"
	"os"
	"strings"
)
func main() {
	conn, err := ("tcp", "127.0.0.1:20003")
	if err != nil {
		("conn err", ())
		return
	}
	defer ()
	inputreader := ()
	for {
		input, _ := ('\n')
		input = (input, "\r\n")
		if input == "q" || input == "Q" {
			("Exit Link")
			return
		}
		([]byte(input))
		var p [512]byte
		n, err := (p[:])
		if err != nil {
			if err ==  {
				("Server-side Close Link", ().String())
				return
			}
			("Read failed", ())
			return
		}
		("The server sends a message as", string(p[:n]))
	}
}

3.3 Sticking problem

Only fixed-length data can be read at a time, solution:

package main
import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
)
func Encode(massge string) ([]byte, error) {
	len_for_msaaget := int32(len(massge))
	pkg := new()
	err := (pkg, , len_for_msaaget)
	if err != nil {
		return nil, err
	}
	err = (pkg, , []byte(massge))
	if err != nil {
		return nil, err
	}
	return (), nil
}
func Decode(reader *) (string, error) {
	peek, err := (4)
	if err != nil {
		return "", err
	}
	lengthBuff := (peek)
	var length int32
	err = (lengthBuff, , &length)
	if err != nil {
		return "", err
	}
	if int32(()) <= 4+length {
		return "", ("err")
	}
	p := make([]byte, int(4+length))
	_, err = (p)
	if err != nil {
		return "", err
	}
	return string(p[4:]), nil
}

3.4 Simple udp request implementation

3.4.1 Server

package main
import (
	"log"
	"net"
)
func main() {
	udp, err := ("udp", &amp;{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: 30000,
	})
	if err != nil {
		return
	}
	defer ()
	for {
		var p [1024]byte
		n, addr, err := (p[:])
		if err != nil {
			("UDP request handling exception", ())
			return
		}
		("Request information", string(p[:n]), ())
		_, err = ([]byte("get"), addr)
		if err != nil {
			("Return information failed", ())
			return
		}
	}
}

3.4.2 Client

package main
import (
	"log"
	"net"
)
func main() {
	udp, err := ("udp", nil, &amp;{
		IP:   net.IPv4(0, 0, 0, 0),
		Port: 30000,
	})
	if err != nil {
		(())
		return
	}
	defer ()
	_, err = ([]byte("I'm a server, hello server"))
	if err != nil {
		(())
		return
	}
	data := make([]byte, 4096)
	fromUDP, u, err := (data)
	if err != nil {
		("Receive failed", err)
		return
	}
	("Received information returned successfully", string([]byte(data[:fromUDP])), u)
}

This is the end of this article about the detailed explanation of the use of net/http packages in Go. For more related Go net/http package content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!