Spec-Zone.ru › Go

Пакет httputil

  • import "net/http/httputil"
  • Обзор
  • Указатель
  • Примеры

Обзор

Пакет httputil предоставляет вспомогательные функции для HTTP, дополняющие более распространённые функции пакета net/http.

Указатель

  • Переменные
  • func DumpRequest(req *http.Request, body bool) ([]byte, error)
  • func DumpRequestOut(req *http.Request, body bool) ([]byte, error)
  • func DumpResponse(resp *http.Response, body bool) ([]byte, error)
  • func NewChunkedReader(r io.Reader) io.Reader
  • func NewChunkedWriter(w io.Writer) io.WriteCloser
  • type BufferPool
  • type ClientConn
  • func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn
  • func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn
  • func (cc *ClientConn) Close() error
  • func (cc *ClientConn) Do(req *http.Request) (*http.Response, error)
  • func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader)
  • func (cc *ClientConn) Pending() int
  • func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error)
  • func (cc *ClientConn) Write(req *http.Request) error
  • type ProxyRequest
  • func (r *ProxyRequest) SetURL(target *url.URL)
  • func (r *ProxyRequest) SetXForwarded()
  • type ReverseProxy
  • func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy
  • func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)
  • type ServerConn
  • func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn
  • func (sc *ServerConn) Close() error
  • func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader)
  • func (sc *ServerConn) Pending() int
  • func (sc *ServerConn) Read() (*http.Request, error)
  • func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error

Примеры

DumpRequest
DumpRequestOut
DumpResponse
ReverseProxy

Файлы пакета

dump.go httputil.go persist.go reverseproxy.go

Переменные

var (
    // Deprecated: No longer used.
    ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}

    // Deprecated: No longer used.
    ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}

    // Deprecated: No longer used.
    ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)

ErrLineTooLong возвращается при чтении некорректных фрагментированных данных, содержащих слишком длинные строки.

var ErrLineTooLong = internal.ErrLineTooLong

func DumpRequest

func DumpRequest(req *http.Request, body bool) ([]byte, error)

DumpRequest возвращает данный запрос в его сетевом представлении HTTP/1.x. Эту функцию следует использовать только на серверах для отладки клиентских запросов. Возвращаемое представление является лишь приближённым: некоторые детали исходного запроса теряются при его разборе в http.Request. В частности, теряются порядок и регистр имён полей заголовка. Порядок значений в заголовках с несколькими значениями сохраняется. Запросы HTTP/2 выводятся в формате HTTP/1.x, а не в исходном двоичном представлении.

Если body имеет значение true, DumpRequest также возвращает тело запроса. Для этого функция считывает req.Body, а затем заменяет его новым io.ReadCloser, который возвращает те же байты. Если DumpRequest возвращает ошибку, состояние req не определено.

В документации к http.Request.Write указано, какие поля req включаются в дамп.

Пример

Код:

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    dump, err := httputil.DumpRequest(r, true)
    if err != nil {
        http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "%q", dump)
}))
defer ts.Close()

const body = "Go is a general-purpose language designed with systems programming in mind."
req, err := http.NewRequest("POST", ts.URL, strings.NewReader(body))
if err != nil {
    log.Fatal(err)
}
req.Host = "www.example.org"
resp, err := http.DefaultClient.Do(req)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

b, err := io.ReadAll(resp.Body)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%s", b)

Вывод:

"POST / HTTP/1.1\r\nHost: www.example.org\r\nAccept-Encoding: gzip\r\nContent-Length: 75\r\nUser-Agent: Go-http-client/1.1\r\n\r\nGo is a general-purpose language designed with systems programming in mind."

func DumpRequestOut

func DumpRequestOut(req *http.Request, body bool) ([]byte, error)

DumpRequestOut похожа на DumpRequest, но предназначена для исходящих клиентских запросов. Она включает заголовки, добавляемые стандартным http.Transport, например User-Agent.

Пример

Код:

const body = "Go is a general-purpose language designed with systems programming in mind."
req, err := http.NewRequest("PUT", "http://www.example.org", strings.NewReader(body))
if err != nil {
    log.Fatal(err)
}

dump, err := httputil.DumpRequestOut(req, true)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%q", dump)

Вывод:

"PUT / HTTP/1.1\r\nHost: www.example.org\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 75\r\nAccept-Encoding: gzip\r\n\r\nGo is a general-purpose language designed with systems programming in mind."

func DumpResponse

func DumpResponse(resp *http.Response, body bool) ([]byte, error)

DumpResponse похожа на DumpRequest, но создаёт дамп ответа.

Пример

Код:

const body = "Go is a general-purpose language designed with systems programming in mind."
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Date", "Wed, 19 Jul 1972 19:00:00 GMT")
    fmt.Fprintln(w, body)
}))
defer ts.Close()

resp, err := http.Get(ts.URL)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

dump, err := httputil.DumpResponse(resp, true)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%q", dump)

Вывод:

"HTTP/1.1 200 OK\r\nContent-Length: 76\r\nContent-Type: text/plain; charset=utf-8\r\nDate: Wed, 19 Jul 1972 19:00:00 GMT\r\n\r\nGo is a general-purpose language designed with systems programming in mind.\n"

func NewChunkedReader

func NewChunkedReader(r io.Reader) io.Reader

NewChunkedReader возвращает новый chunkedReader, который преобразует считываемые из r данные из формата HTTP «chunked», прежде чем вернуть их. chunkedReader возвращает io.EOF при чтении последнего фрагмента нулевой длины.

Обычным приложениям NewChunkedReader не требуется. Пакет http автоматически декодирует фрагментированные данные при чтении тел ответов.

func NewChunkedWriter

func NewChunkedWriter(w io.Writer) io.WriteCloser

NewChunkedWriter возвращает новый chunkedWriter, который преобразует записываемые данные в формат HTTP «chunked», прежде чем записать их в w. Закрытие возвращённого chunkedWriter отправляет последний фрагмент нулевой длины, обозначающий конец потока, но не отправляет завершающий CRLF после трейлеров; трейлеры и последний CRLF необходимо записать отдельно.

Обычным приложениям NewChunkedWriter не требуется. Пакет http автоматически добавляет фрагментацию, если обработчики не устанавливают заголовок Content-Length. Использование NewChunkedWriter внутри обработчика приведёт к двойной фрагментации или фрагментации с указанной длиной Content-Length; оба варианта некорректны.

type BufferPool 1.6

BufferPool — это интерфейс для получения и возврата временных срезов байтов, используемых функцией io.CopyBuffer.

type BufferPool interface {
    Get() []byte
    Put([]byte)
}

type ClientConn

ClientConn — это артефакт ранней реализации HTTP в Go. Это низкоуровневый устаревший компонент, не используемый в текущем HTTP-стеке Go. Его следовало удалить до выхода Go 1.

Устарело: вместо этого используйте Client или Transport из пакета net/http.

type ClientConn struct {
    // contains filtered or unexported fields
}

func NewClientConn

func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn

NewClientConn — это артефакт ранней реализации HTTP в Go. Это низкоуровневый устаревший компонент, не используемый в текущем HTTP-стеке Go. Его следовало удалить до выхода Go 1.

Устарело: вместо этого используйте Client или Transport из пакета net/http.

func NewProxyClientConn

func NewProxyClientConn(c net.Conn, r *bufio.Reader) *ClientConn

NewProxyClientConn — это артефакт ранней реализации HTTP в Go. Это низкоуровневый устаревший компонент, не используемый в текущем HTTP-стеке Go. Его следовало удалить до выхода Go 1.

Устарело: вместо этого используйте Client или Transport из пакета net/http.

func (*ClientConn) Close

func (cc *ClientConn) Close() error

Close вызывает ClientConn.Hijack, а затем также закрывает базовое соединение.

func (*ClientConn) Do

func (cc *ClientConn) Do(req *http.Request) (*http.Response, error)

Do — это вспомогательный метод, который записывает запрос и читает ответ.

func (*ClientConn) Hijack

func (cc *ClientConn) Hijack() (c net.Conn, r *bufio.Reader)

Hijack отсоединяет ClientConn и возвращает базовое соединение, а также bufio для чтения, в котором могут оставаться непрочитанные данные. Hijack можно вызвать до того, как пользователь или Read сообщили об окончании логики keep-alive. Не следует вызывать Hijack, пока выполняется ClientConn.Read или ClientConn.Write.

func (*ClientConn) Pending

func (cc *ClientConn) Pending() int

Pending возвращает количество отправленных через соединение запросов, на которые ещё не получены ответы.

func (*ClientConn) Read

func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error)

Read читает следующий ответ из сети. Допустимый ответ может быть возвращён вместе с ErrPersistEOF, что означает, что удалённая сторона запросила, чтобы этот запрос был последним обработанным. Read можно вызывать одновременно с ClientConn.Write, но не одновременно с другим вызовом Read.

func (*ClientConn) Write

func (cc *ClientConn) Write(req *http.Request) error

Write записывает запрос. Ошибка ErrPersistEOF возвращается, если соединение закрыто с точки зрения HTTP keep-alive. Если req.Close равно true, keep-alive-соединение логически закрывается после этого запроса, и серверу на другой стороне сообщается об этом. ErrUnexpectedEOF указывает на то, что удалённая сторона закрыла базовое TCP-соединение; обычно это считается штатным закрытием.

type ProxyRequest 1.20

ProxyRequest содержит запрос, который должен быть переписан с помощью ReverseProxy.

type ProxyRequest struct {
    // In is the request received by the proxy.
    // The Rewrite function must not modify In.
    In *http.Request

    // Out is the request which will be sent by the proxy.
    // The Rewrite function may modify or replace this request.
    // Hop-by-hop headers are removed from this request
    // before Rewrite is called.
    Out *http.Request
}

func (*ProxyRequest) SetURL 1.20

func (r *ProxyRequest) SetURL(target *url.URL)

SetURL направляет исходящий запрос на схему, хост и базовый путь, указанные в target. Если путь target — "/base", а входящий запрос был для "/dir", целевой запрос будет направлен на "/base/dir". Чтобы направлять запросы без объединения с входящим путём, задайте r.Out.URL напрямую.

SetURL переписывает заголовок Host исходящего запроса, чтобы он соответствовал хосту target. Чтобы сохранить заголовок Host входящего запроса (поведение по умолчанию для NewSingleHostReverseProxy):

rewriteFunc := func(r *httputil.ProxyRequest) {
	r.SetURL(url)
	r.Out.Host = r.In.Host
}

func (*ProxyRequest) SetXForwarded 1.20

func (r *ProxyRequest) SetXForwarded()

SetXForwarded задаёт заголовки X-Forwarded-For, X-Forwarded-Host и X-Forwarded-Proto исходящего запроса.

  • Заголовку X-Forwarded-For присваивается IP-адрес клиента.
  • Заголовку X-Forwarded-Host присваивается имя хоста, запрошенное клиентом.
  • Заголовку X-Forwarded-Proto присваивается значение "http" или "https" в зависимости от того, было ли входящее соединение защищено с помощью TLS.

Если исходящий запрос уже содержит заголовок X-Forwarded-For, SetXForwarded добавляет к нему IP-адрес клиента. Чтобы добавить адрес к заголовку X-Forwarded-For входящего запроса (поведение по умолчанию для ReverseProxy при использовании функции Director), скопируйте заголовок из входящего запроса перед вызовом SetXForwarded:

rewriteFunc := func(r *httputil.ProxyRequest) {
	r.Out.Header["X-Forwarded-For"] = r.In.Header["X-Forwarded-For"]
	r.SetXForwarded()
}

type ReverseProxy

ReverseProxy — это HTTP-обработчик, который принимает входящий запрос, отправляет его другому серверу и передаёт полученный ответ обратно клиенту.

Ответы 1xx передаются клиенту, если используемый транспорт поддерживает ClientTrace.Got1xxResponse.

Заголовки, относящиеся только к одному переходу (см. RFC 9110, раздел 7.6.1), включая Connection, Proxy-Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailer, Transfer-Encoding и Upgrade, удаляются из запросов клиентов и ответов серверов. Функцию Rewrite можно использовать для добавления таких заголовков в запрос, а функцию ModifyResponse — для их удаления из ответа.

type ReverseProxy struct {
    // Rewrite must be a function which modifies
    // the request into a new request to be sent
    // using Transport. Its response is then copied
    // back to the original client unmodified.
    // Rewrite must not access the provided ProxyRequest
    // or its contents after returning.
    //
    // The Forwarded, X-Forwarded, X-Forwarded-Host,
    // and X-Forwarded-Proto headers are removed from the
    // outbound request before Rewrite is called. See also
    // the ProxyRequest.SetXForwarded method.
    //
    // Unparsable query parameters are removed from the
    // outbound request before Rewrite is called.
    // The Rewrite function may copy the inbound URL's
    // RawQuery to the outbound URL to preserve the original
    // parameter string. Note that this can lead to security
    // issues if the proxy's interpretation of query parameters
    // does not match that of the downstream server.
    //
    // At most one of Rewrite or Director may be set.
    Rewrite func(*ProxyRequest) // Go 1.20

    // The transport used to perform proxy requests.
    // If nil, http.DefaultTransport is used.
    Transport http.RoundTripper

    // FlushInterval specifies the flush interval
    // to flush to the client while copying the
    // response body.
    // If zero, no periodic flushing is done.
    // A negative value means to flush immediately
    // after each write to the client.
    // The FlushInterval is ignored when ReverseProxy
    // recognizes a response as a streaming response, or
    // if its ContentLength is -1; for such responses, writes
    // are flushed to the client immediately.
    FlushInterval time.Duration

    // ErrorLog specifies an optional logger for errors
    // that occur when attempting to proxy the request.
    // If nil, logging is done via the log package's standard logger.
    ErrorLog *log.Logger // Go 1.4

    // BufferPool optionally specifies a buffer pool to
    // get byte slices for use by io.CopyBuffer when
    // copying HTTP response bodies.
    BufferPool BufferPool // Go 1.6

    // ModifyResponse is an optional function that modifies the
    // Response from the backend. It is called if the backend
    // returns a response at all, with any HTTP status code.
    // If the backend is unreachable, the optional ErrorHandler is
    // called without any call to ModifyResponse.
    //
    // Hop-by-hop headers are removed from the response before
    // calling ModifyResponse. ModifyResponse may need to remove
    // additional headers to fit its deployment model, such as Alt-Svc.
    //
    // If ModifyResponse returns an error, ErrorHandler is called
    // with its error value. If ErrorHandler is nil, its default
    // implementation is used.
    ModifyResponse func(*http.Response) error // Go 1.8

    // ErrorHandler is an optional function that handles errors
    // reaching the backend or errors from ModifyResponse.
    //
    // If nil, the default is to log the provided error and return
    // a 502 Status Bad Gateway response.
    ErrorHandler func(http.ResponseWriter, *http.Request, error) // Go 1.11

    // Director is deprecated. Use Rewrite instead.
    //
    // This function is insecure:
    //
    //   - Hop-by-hop headers are removed from the request after Director
    //     returns, which can remove headers added by Director.
    //     A client can designate headers as hop-by-hop by listing them
    //     in the Connection header, so this permits a malicious client
    //     to remove any headers that may be added by Director.
    //
    //   - X-Forwarded-For, X-Forwarded-Host, and X-Forwarded-Proto
    //     headers in inbound requests are preserved by default,
    //     which can permit IP spoofing if the Director function is
    //     not careful to remove these headers.
    //
    // Rewrite addresses these issues.
    //
    // As an example of converting a Director function to Rewrite:
    //
    //	// ReverseProxy with a Director function.
    //	proxy := &httputil.ReverseProxy{
    //		Director: func(req *http.Request) {
    //			req.URL.Scheme = "https"
    //			req.URL.Host = proxyHost
    //
    //			// A malicious client can remove this header.
    //			req.Header.Set("Some-Header", "some-header-value")
    //
    //			// X-Forwarded-* headers sent by the client are preserved,
    //			// since Director did not remove them.
    //		},
    //	}
    //
    //	// ReverseProxy with a Rewrite function.
    //	proxy := &httputil.ReverseProxy{
    //		Rewrite: func(preq *httputil.ProxyRequest) {
    //			// See also ProxyRequest.SetURL.
    //			preq.Out.URL.Scheme = "https"
    //			preq.Out.URL.Host = proxyHost
    //
    //			// This header cannot be affected by a malicious client.
    //			preq.Out.Header.Set("Some-Header", "some-header-value")
    //
    //			// X-Forwarded- headers sent by the client have been
    //			// removed from preq.Out.
    //			// ProxyRequest.SetXForwarded optionally adds new ones.
    //			preq.SetXForwarded()
    //		},
    //	}
    //
    // Director is a function which modifies
    // the request into a new request to be sent
    // using Transport. Its response is then copied
    // back to the original client unmodified.
    // Director must not access the provided Request
    // after returning.
    //
    // By default, the X-Forwarded-For header is set to the
    // value of the client IP address. If an X-Forwarded-For
    // header already exists, the client IP is appended to the
    // existing values. As a special case, if the header
    // exists in the Request.Header map but has a nil value
    // (such as when set by the Director func), the X-Forwarded-For
    // header is not modified.
    //
    // To prevent IP spoofing, be sure to delete any pre-existing
    // X-Forwarded-For header coming from the client or
    // an untrusted proxy.
    //
    // Hop-by-hop headers are removed from the request after
    // Director returns, which can remove headers added by
    // Director. Use a Rewrite function instead to ensure
    // modifications to the request are preserved.
    //
    // Unparsable query parameters are removed from the outbound
    // request if Request.Form is set after Director returns.
    //
    // At most one of Rewrite or Director may be set.
    //
    // Deprecated: Use Rewrite instead.
    Director func(*http.Request)
}

Пример

Код:

backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "this call was relayed by the reverse proxy")
}))
defer backendServer.Close()

rpURL, err := url.Parse(backendServer.URL)
if err != nil {
    log.Fatal(err)
}
frontendProxy := httptest.NewServer(&httputil.ReverseProxy{
    Rewrite: func(r *httputil.ProxyRequest) {
        r.SetXForwarded()
        r.SetURL(rpURL)
    },
})
defer frontendProxy.Close()

resp, err := http.Get(frontendProxy.URL)
if err != nil {
    log.Fatal(err)
}

b, err := io.ReadAll(resp.Body)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%s", b)

Вывод:

this call was relayed by the reverse proxy

func NewSingleHostReverseProxy

func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy

NewSingleHostReverseProxy возвращает новый ReverseProxy, который направляет URL-адреса на схему, хост и базовый путь, указанные в target. Если путь target — "/base", а входящий запрос был для "/dir", целевой запрос будет направлен на /base/dir.

NewSingleHostReverseProxy не переписывает заголовок Host.

Для обратной совместимости NewSingleHostReverseProxy возвращает ReverseProxy, использующий устаревшую функцию Director. Этот прокси сохраняет заголовки X-Forwarded-*, отправленные клиентом.

Чтобы настроить поведение ReverseProxy сверх возможностей NewSingleHostReverseProxy, используйте ReverseProxy напрямую с функцией Rewrite. Для маршрутизации исходящего запроса можно использовать метод ProxyRequest SetURL. (Обратите внимание: в отличие от NewSingleHostReverseProxy, SetURL по умолчанию переписывает заголовок Host исходящего запроса.)

proxy := &ReverseProxy{
	Rewrite: func(r *ProxyRequest) {
		r.SetURL(target)
		r.Out.Host = r.In.Host // if desired
	},
}

func (*ReverseProxy) ServeHTTP

func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)

type ServerConn

ServerConn — это пережиток ранней реализации HTTP в Go. Это низкоуровневый устаревший элемент, не используемый в текущем стеке HTTP Go. Его следовало удалить до выпуска Go 1.

Устарело: вместо этого используйте Server из пакета net/http.

type ServerConn struct {
    // contains filtered or unexported fields
}

func NewServerConn

func NewServerConn(c net.Conn, r *bufio.Reader) *ServerConn

NewServerConn — это пережиток ранней реализации HTTP в Go. Это низкоуровневый устаревший элемент, не используемый в текущем стеке HTTP Go. Его следовало удалить до выпуска Go 1.

Устарело: вместо этого используйте Server из пакета net/http.

func (*ServerConn) Close

func (sc *ServerConn) Close() error

Close вызывает ServerConn.Hijack, а затем также закрывает базовое соединение.

func (*ServerConn) Hijack

func (sc *ServerConn) Hijack() (net.Conn, *bufio.Reader)

Hijack отсоединяет ServerConn и возвращает базовое соединение, а также bufio для чтения, в котором могут оставаться непрочитанные данные. Hijack можно вызвать до того, как Read сообщит об окончании логики keep-alive. Не следует вызывать Hijack, пока выполняется ServerConn.Read или ServerConn.Write.

func (*ServerConn) Pending

func (sc *ServerConn) Pending() int

Pending возвращает количество запросов, полученных через соединение, на которые ещё не отправлены ответы.

func (*ServerConn) Read

func (sc *ServerConn) Read() (*http.Request, error)

Read возвращает следующий запрос из сети. Ошибка ErrPersistEOF возвращается, если достоверно установлено, что больше запросов не будет (например, после первого запроса в соединении HTTP/1.0 или после Connection:close в соединении HTTP/1.1).

func (*ServerConn) Write

func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error

Write записывает resp в ответ на req. Чтобы корректно закрыть соединение, установите для поля Response.Close значение true. Следует считать, что Write работает, пока он не вернёт ошибку, независимо от ошибок, возвращённых методом ServerConn.Read.

© Google, Inc.
Licensed under the Creative Commons Attribution License 3.0.
http://golang.org/pkg/net/http/httputil/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API