获取“127.0.0.1无法分配请求的地址” – http.Client

我正在做的事情是相当直接的.我需要创建一个非常小而快的“代理”服务器.目前我有一个代理到(nodejs)和代理服务(go)的基线服务器.请原谅缺乏实际的“代理” – 只是现在测试.

基线服务

var http = require('http');
http.createServer(function (req, res) {
    // console.log("received request");
    res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('Hello World\n');
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');

代理服务

package main

import (
  "flag"
  "log"
  "net/http"
  "net/url"
)

var (
  listen = flag.String("listen", "0.0.0.0:9000", "listen on address")
  logp = flag.Bool("log", false, "enable logging")
)

func main() {
  flag.Parse()
  proxyHandler := http.HandlerFunc(proxyHandlerFunc)
  log.Fatal(http.ListenAndServe(*listen, proxyHandler))
  log.Println("Started router-server on 0.0.0.0:9000")
}

func proxyHandlerFunc(w http.ResponseWriter, r *http.Request) {
  // Log if requested
  if *logp {
    log.Println(r.URL)
  }

  /* 
   * Tweak the request as appropriate:
   *   - RequestURI may not be sent to client
   *   - Set new URL
   */
  r.RequestURI = ""
  u, err := url.Parse("http://localhost:8080/")
  if err != nil {
    log.Fatal(err)
  }
  r.URL = u

  // And proxy
  // resp, err := client.Do(r)
  c := make(chan *http.Response)
  go doRequest(c)
  resp := <-c
  if resp != nil {
    err := resp.Write(w)
    if err != nil {
      log.Println("Error writing response")
    } else {
      resp.Body.Close()
    }
  }
}


func doRequest(c chan *http.Response) {
  // new client for every request.
  client := &http.Client{}

  resp, err := client.Get("http://127.0.0.1:8080/test")
  if err != nil {
    log.Println(err)
    c <- nil
  } else {
    c <- resp
  }
}

我在标题中提到的问题是,我收到错误说明2013/10/28 21:22:30获取http://127.0.0.1:8080/test:拨打tcp 127.0.0.1:8080:不能从doRequest函数分配请求的地址,我不知道为什么.谷歌搜索这个特定的错误产生看似无关的结果.

最佳答案
这段代码有两个主要问题.

>您没有处理客户端停止或使用keep alives(由getTimeoutServer在下面处理)
>您没有处理服务器(您的http.Client正在与之交谈)超时(由TimeoutConn在下面处理).

这可能是您耗尽本地端口的原因.我从过去的经验中知道node.js会非常积极地保持活力.

有许多小问题,在不需要的时候每次创建对象.创建不需要的goroutine(每个传入的请求在你处理它之前都在它自己的goroutine中).

这是一个快速刺(我没时间测试好).希望它会让你走上正确的轨道:(你会想要升级它以不在本地缓冲响应)

package main

import (
    "bytes"
    "errors"
    "flag"
    "fmt"
    "log"
    "net"
    "net/http"
    "net/url"
    "runtime"
    "strconv"
    "time"
)

const DEFAULT_IDLE_TIMEOUT = 5 * time.Second

var (
    listen       string
    logOn        bool
    localhost, _ = url.Parse("http://localhost:8080/")
    client       = &http.Client{
        Transport: &http.Transport{
            Proxy: NoProxyAllowed,
            Dial: func(network, addr string) (net.Conn, error) {
                return NewTimeoutConnDial(network, addr, DEFAULT_IDLE_TIMEOUT)
            },
        },
    }
)

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    flag.StringVar(&listen, "listen", "0.0.0.0:9000", "listen on address")
    flag.BoolVar(&logOn, "log", true, "enable logging")
    flag.Parse()
    server := getTimeoutServer(listen, http.HandlerFunc(proxyHandlerFunc))
    log.Printf("Starting router-server on %s\n", listen)
    log.Fatal(server.ListenAndServe())
}

func proxyHandlerFunc(w http.ResponseWriter, req *http.Request) {
    if logOn {
        log.Printf("%+v\n", req)
    }
    // Setup request URL
    origURL := req.URL
    req.URL = new(url.URL)
    *req.URL = *localhost
    req.URL.Path, req.URL.RawQuery, req.URL.Fragment = origURL.Path, origURL.RawQuery, origURL.Fragment
    req.RequestURI, req.Host = "", req.URL.Host
    // Perform request
    resp, err := client.Do(req)
    if err != nil {
        w.WriteHeader(http.StatusBadGateway)
        w.Write([]byte(fmt.Sprintf("%d - StatusBadGateway: %s", http.StatusBadGateway, err)))
        return
    }
    defer resp.Body.Close()
    var respBuffer *bytes.Buffer
    if resp.ContentLength != -1 {
        respBuffer = bytes.NewBuffer(make([]byte, 0, resp.ContentLength))
    } else {
        respBuffer = new(bytes.Buffer)
    }
    if _, err = respBuffer.ReadFrom(resp.Body); err != nil {
        w.WriteHeader(http.StatusBadGateway)
        w.Write([]byte(fmt.Sprintf("%d - StatusBadGateway: %s", http.StatusBadGateway, err)))
        return
    }
    // Write result of request
    headers := w.Header()
    var key string
    var val []string
    for key, val = range resp.Header {
        headers[key] = val
    }
    headers.Set("Content-Length", strconv.Itoa(respBuffer.Len()))
    w.WriteHeader(resp.StatusCode)
    w.Write(respBuffer.Bytes())
}

func getTimeoutServer(addr string, handler http.Handler) *http.Server {
    //keeps people who are slow or are sending keep-alives from eating all our sockets
    const (
        HTTP_READ_TO  = DEFAULT_IDLE_TIMEOUT
        HTTP_WRITE_TO = DEFAULT_IDLE_TIMEOUT
    )
    return &http.Server{
        Addr:         addr,
        Handler:      handler,
        ReadTimeout:  HTTP_READ_TO,
        WriteTimeout: HTTP_WRITE_TO,
    }
}

func NoProxyAllowed(request *http.Request) (*url.URL, error) {
    return nil, nil
}

//TimeoutConn-------------------------
//Put me in my own TimeoutConn.go ?

type TimeoutConn struct {
    net.Conn
    readTimeout, writeTimeout time.Duration
}

var invalidOperationError = errors.New("TimeoutConn does not support or allow .SetDeadline operations")

func NewTimeoutConn(conn net.Conn, ioTimeout time.Duration) (*TimeoutConn, error) {
    return NewTimeoutConnReadWriteTO(conn, ioTimeout, ioTimeout)
}

func NewTimeoutConnReadWriteTO(conn net.Conn, readTimeout, writeTimeout time.Duration) (*TimeoutConn, error) {
    this := &TimeoutConn{
        Conn:         conn,
        readTimeout:  readTimeout,
        writeTimeout: writeTimeout,
    }
    now := time.Now()
    err := this.Conn.SetReadDeadline(now.Add(this.readTimeout))
    if err != nil {
        return nil, err
    }
    err = this.Conn.SetWriteDeadline(now.Add(this.writeTimeout))
    if err != nil {
        return nil, err
    }
    return this, nil
}

func NewTimeoutConnDial(network, addr string, ioTimeout time.Duration) (net.Conn, error) {
    conn, err := net.DialTimeout(network, addr, ioTimeout)
    if err != nil {
        return nil, err
    }
    if conn, err = NewTimeoutConn(conn, ioTimeout); err != nil {
        return nil, err
    }
    return conn, nil
}

func (this *TimeoutConn) Read(data []byte) (int, error) {
    this.Conn.SetReadDeadline(time.Now().Add(this.readTimeout))
    return this.Conn.Read(data)
}

func (this *TimeoutConn) Write(data []byte) (int, error) {
    this.Conn.SetWriteDeadline(time.Now().Add(this.writeTimeout))
    return this.Conn.Write(data)
}

func (this *TimeoutConn) SetDeadline(time time.Time) error {
    return invalidOperationError
}

func (this *TimeoutConn) SetReadDeadline(time time.Time) error {
    return invalidOperationError
}

func (this *TimeoutConn) SetWriteDeadline(time time.Time) error {
    return invalidOperationError
}

转载注明原文:获取“127.0.0.1无法分配请求的地址” – http.Client - 代码日志