geektutu/7days-golang · error

unexpected HTTP response:

Error message

unexpected HTTP response: 

What it means

NewHTTPClient performs the xRPC CONNECT handshake: it sends an HTTP CONNECT request and waits for a response whose status equals the magic "connected" string before switching to the RPC protocol. If the response is HTTP but not the expected status, it wraps the status in "unexpected HTTP response: ". This indicates the server did not recognize the HTTP RPC handshake.

Source

Thrown at gee-rpc/day6-load-balance/client.go:295

}

// Dial connects to an RPC server at the specified network address
func Dial(network, address string, opts ...*Option) (*Client, error) {
	return dialTimeout(NewClient, network, address, opts...)
}

// NewHTTPClient new a Client instance via HTTP as transport protocol
func NewHTTPClient(conn net.Conn, opt *Option) (*Client, error) {
	_, _ = io.WriteString(conn, fmt.Sprintf("CONNECT %s HTTP/1.0\n\n", defaultRPCPath))

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn, opt)
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	return nil, err
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string, opts ...*Option) (*Client, error) {
	return dialTimeout(NewHTTPClient, network, address, opts...)
}

// XDial calls different functions to connect to a RPC server
// according the first parameter rpcAddr.
// rpcAddr is a general format (protocol@addr) to represent a rpc server
// eg, http@10.0.0.1:7001, tcp@10.0.0.1:9999, unix@/tmp/geerpc.sock
func XDial(rpcAddr string, opts ...*Option) (*Client, error) {
	parts := strings.Split(rpcAddr, "@")
	if len(parts) != 2 {
		return nil, fmt.Errorf("rpc client err: wrong format '%s', expect protocol@addr", rpcAddr)

View on GitHub (pinned to cf36443821)

Solutions

  1. Register the HTTP handshake on the server (HandleHTTP) and serve DefaultHTTPRPCPath via http.ListenAndServe
  2. Verify the address/port points to the xRPC HTTP endpoint, not a plain web server or the raw-RPC port
  3. Use Dial (raw TCP) instead of DialHTTP if the server is not an HTTP-handshake server
  4. Check proxies/load balancers that may intercept or rewrite the CONNECT request

Example fix

// before
client, err := geeprc.DialHTTP("tcp", "localhost:9999") // plain TCP rpc server

// after
// server side:
geeprc.HandleHTTP()
http.ListenAndServe("localhost:9999", nil)
// then client:
client, err := geeprc.DialHTTP("tcp", "localhost:9999")
Defensive patterns

Strategy: validation

Validate before calling

// verify the server speaks the xRPC HTTP handshake before dialing
conn, _ := net.DialTimeout("tcp", addr, 3*time.Second)
req, _ := http.NewRequest("CONNECT", "http://"+addr+DefaultHTTPRPCPath, nil)
req.Write(conn)
resp, err := http.ReadResponse(bufio.NewReader(conn), req)
if err != nil || resp.Status != connected {
    return errors.New("endpoint does not support xRPC over HTTP")
}

Try / catch

client, err := geeprc.DialHTTP("tcp", addr)
if err != nil {
    if strings.HasPrefix(err.Error(), "unexpected HTTP response: ") {
        // wrong endpoint/protocol: fall back to raw Dial or fix server registration
    }
    return err
}

Prevention

When it happens

Trigger: DialHTTP/NewHTTPClient against a port that serves plain HTTP (no xRPC handler on DefaultHTTPRPCPath); server not registered via HandleHTTP; wrong path or proxy intercepting CONNECT; connecting a normal (non-HTTP) xRPC server with DialHTTP.

Common situations: Pointing DialHTTP at an ordinary web server or wrong port; forgetting gee-rpc's HandleHTTP registration on the server; a reverse proxy returning 404/502 for the RPC path; version mismatch where the server expects a different handshake string.

Related errors


AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03). Data as JSON: /api/errors/3acc5c553fc0600c. Report an issue: GitHub.