{"record":{"id":"925d2612c4d32777","repo":"geektutu/7days-golang","slug":"unexpected-http-response","errorCode":null,"errorMessage":"unexpected HTTP response: ","messagePattern":"unexpected HTTP response: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-rpc/day5-http-debug/client.go","lineNumber":295,"sourceCode":"}\n\n// Dial connects to an RPC server at the specified network address\nfunc Dial(network, address string, opts ...*Option) (*Client, error) {\n\treturn dialTimeout(NewClient, network, address, opts...)\n}\n\n// NewHTTPClient new a Client instance via HTTP as transport protocol\nfunc NewHTTPClient(conn net.Conn, opt *Option) (*Client, error) {\n\t_, _ = io.WriteString(conn, fmt.Sprintf(\"CONNECT %s HTTP/1.0\\n\\n\", defaultRPCPath))\n\n\t// Require successful HTTP response\n\t// before switching to RPC protocol.\n\tresp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: \"CONNECT\"})\n\tif err == nil && resp.Status == connected {\n\t\treturn NewClient(conn, opt)\n\t}\n\tif err == nil {\n\t\terr = errors.New(\"unexpected HTTP response: \" + resp.Status)\n\t}\n\treturn nil, err\n}\n\n// DialHTTP connects to an HTTP RPC server at the specified network address\n// listening on the default HTTP RPC path.\nfunc DialHTTP(network, address string, opts ...*Option) (*Client, error) {\n\treturn dialTimeout(NewHTTPClient, network, address, opts...)\n}\n\n// XDial calls different functions to connect to a RPC server\n// according the first parameter rpcAddr.\n// rpcAddr is a general format (protocol@addr) to represent a rpc server\n// eg, http@10.0.0.1:7001, tcp@10.0.0.1:9999, unix@/tmp/geerpc.sock\nfunc XDial(rpcAddr string, opts ...*Option) (*Client, error) {\n\tparts := strings.Split(rpcAddr, \"@\")\n\tif len(parts) != 2 {\n\t\treturn nil, fmt.Errorf(\"rpc client err: wrong format '%s', expect protocol@addr\", rpcAddr)","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-rpc/day5-http-debug/client.go#L277-L313","documentation":"NewHTTPClient dials the server using the HTTP CONNECT protocol and expects the server to reply with the exact status line \"200 Connected to Gee RPC\" before the connection is switched to the RPC protocol. If the server's response is a valid HTTP response with any other status, this error is thrown so the caller knows the handshake failed.","triggerScenarios":"DialHTTP/NewHTTPClient is pointed at: (1) an endpoint that is not a gee-rpc HTTP-mode server, (2) a server built with the plain (non-HTTP) NewServer/Listen instead of NewHTTPServer/HTTP registry, or (3) a proxy/load balancer that answers CONNECT with its own status line.","commonSituations":"Connecting to a regular TCP gee-rpc port with DialHTTP, hitting the wrong port behind an nginx/HAProxy that intercepts the request, or a misconfigured service registry pointing to an HTTP health endpoint instead of the RPC endpoint.","solutions":["Start the server in HTTP mode (NewHTTPServer / http.Handle with gee-rpc's HTTPCodecConn or XPrt-based handler) so it answers CONNECT with the expected status","Verify the address/port in DialHTTP points at the RPC server, not another HTTP service or proxy","Bypass or reconfigure proxies on that port so the CONNECT request reaches the gee-rpc server directly","Check the server log for the exact resp.Status to confirm who sent the unexpected response"],"exampleFix":"// before\nconn, err := net.Dial(\"tcp\", addr) // server is a plain TCP rpc server\nclient, err := geeprc.NewHTTPClient(conn)\n// after\nlis, _ := net.Listen(\"tcp\", addr) // on server side, run HTTP-mode server\nsrv := geeprc.NewHTTPServer()\nhttp.Handle(\"/_geerpc_\", srv)\n// then connect with NewHTTPClient / DialHTTP to the correct address","handlingStrategy":"fallback","validationCode":"addr := \"localhost:9999\"\nif u, err := url.Parse(addr); err == nil && u.Scheme != \"\" {\n    addr = u.Host // ensure raw host:port, not a URL\n}","typeGuard":null,"tryCatchPattern":"client, err := geeprc.DialHTTP(\"tcp\", addr)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected HTTP response\") {\n        // retry with plain NewClient (non-HTTP mode) or fail fast with a clear message\n        return fmt.Errorf(\"%s is not an HTTP-mode rpc server: %w\", addr, err)\n    }\n    return err\n}","preventionTips":["Run the server in HTTP mode (NewHTTPServer) whenever clients use DialHTTP/NewHTTPClient","Smoke-test the endpoint's CONNECT handshake in CI before deployment","Pin RPC addresses away from proxies/load balancers, or configure the proxy to pass CONNECT through"],"tags":["network","http","rpc","handshake"],"backgroundTag":"unexpected-http-response","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}