Implementing a Custom DNS Resolver for Go HTTP Client Testing
This article demonstrates how to extend Go's HTTP client with a custom DNS resolver using net.Dialer, configure load‑balancing, and test the implementation with sample code and a simple mock service, providing a practical guide for backend developers.
After completing Java custom DNS resolver articles, I explored the same functionality for Go's HTTP testing, ultimately implementing a custom DNS resolver using the standard http library (with fasthttp to be covered later).
Setting net.Dialer
First, the net.Dialer (the dialing component for establishing HTTP connections) is configured similarly to Java's HttpClient connection manager.
func clients() http.Client {
dialer := &net.Dialer{Timeout: 1 * time.Second}
return http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
MaxIdleConnsPerHost: 200,
MaxConnsPerHost: 10000,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
DialContext: dialer.DialContext,
},
}
}Strange Knowledge Point
Go's net/http library also supports binding a DNS service IP, which can direct requests for a fixed domain to a specific machine.
dialer := &net.Dialer{Timeout: 1 * time.Second}
dialer.Resolver = &net.Resolver{Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
return dialer.DialContext(ctx, "tcp", "114.114.114.114:53") // use custom nameserver
},}Custom net.Dialer
The http.Transport struct includes a DialContext field, a function used to create raw TCP connections. By providing a custom closure, we can intercept connections and perform DNS‑based load balancing.
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
host, port, err := net.SplitHostPort(address)
if err != nil { return nil, err }
// Example: redirect "fun.tester" to 127.0.0.1
if host == "fun.tester" {
ip := "127.0.0.1"
log.Println(ip)
conn, err := dialer.DialContext(ctx, network, ip+":"+port)
if err == nil { return conn, nil }
}
return dialer.DialContext(ctx, network, address)
},Test
A simple test case creates a request to the custom host and prints the response.
// TestFaast
func TestFaast(t *testing.T) {
url := "http://fun.tester:12345/test"
get := fhttp.Get(url, nil)
response := fhttp.Response(get)
log.Println(string(response))
}Console output shows the request being routed to 127.0.0.1 and the expected response.
=== RUN TestFaast
2022/02/07 15:34:47 127.0.0.1
2022/02/07 15:34:48 Have Fun ~ Tester !
--- PASS: TestFaast (0.31s)
PASSTest Service
The test service is a simple mock built with the moco_FunTester framework.
static void main(String[] args) {
def util = new ArgsUtil(args)
def server = getServerNoLog(util.getIntOrdefault(0, 12345))
server.response(delay(textRes("Have Fun ~ Tester !"), 100))
def run = run(server)
waitForKey("fan")
run.stop()
}FunTester 2021 Summary
FunTester Original Works
Groovy Language Notes
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
