переписать длину содержимого в промежуточном программном обеспечении - PullRequest
2 голосов
/ 08 марта 2019

ниже кода переписывает http-ответ тела на некоторые запросы.

Однако не удается обновить поле заголовка «длина содержимого», оно всегда остается прежним исходным значением.

Как можноя обновляю поле заголовка длины содержимого ответа http?

type writeReplacer struct {
    http.ResponseWriter
    search  []byte
    replace func(*http.Request) string
    buf     []byte
    r       *http.Request
    dir     string
}

func (w *writeReplacer) Write(in []byte) (int, error) {
    if w.buf == nil {
        w.buf = []byte{}
    }
    w.buf = append(w.buf, in...)
    n := len(in)
    if index := bytes.LastIndex(w.buf, w.search); index > -1 {
        var r []byte
        if w.dir == "before" {
            g := []byte(w.replace(w.r))
            n += len(g)
            r = append(g, w.buf[index:]...)
            w.buf = append(w.buf[:index], r...)
        } else {
            g := []byte(w.replace(w.r))
            n += len(g)
            r = append(r, w.buf[:index+len(w.search)]...)
            r = append(r, g...)
            r = append(r, w.buf[index:]...)
            w.buf = r
        }
    }
    return n, nil
}

func (w *writeReplacer) Flush() {
    w.ResponseWriter.Header().Set("Content-Length", fmt.Sprint(len(w.buf)))
    w.ResponseWriter.Write(w.buf[:])
    w.buf = w.buf[:0]
}

func InsertAfter(h http.Handler, path string, search []byte, replace func(*http.Request) string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path == path {
            w.Header().Del("Content-length")
            w = &writeReplacer{ResponseWriter: w, search: search, replace: replace, r: r, dir: "after"}
            defer w.(http.Flusher).Flush()
        }
        h.ServeHTTP(w, r)
    })
}

func InsertBefore(h http.Handler, path string, search []byte, replace func(*http.Request) string) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if r.URL.Path == path {
            w.Header().Del("Content-length")
            w = &writeReplacer{ResponseWriter: w, search: search, replace: replace, r: r, dir: "before"}
            defer w.(http.Flusher).Flush()
        }
        h.ServeHTTP(w, r)
    })
}

Я получаю два сообщения об ошибке: первое от nginx

2019/03/08 05:58:37 [error] 31194#0: *19 
upstream prematurely closed connection while reading upstream, 
client: 82.21.18.16, server: buycoffee.online, request: 
"GET / HTTP/1.1", upstream: "http://127.0.0.1:8081/", host: "buycoffee.online"

, второе от curl

curl: (18) transfer closed with 6237 bytes remaining to read

1 Ответ

0 голосов
/ 08 марта 2019

как подсказал mkopriva, уловка была в том, чтобы переписать ResponseWriter.WriteHeader.

Я полагаю, что это связано с тем, что write может вызвать writeheader при первом вызове, и оттуда я не помещал инструкции в нужное место.

Во избежание дальнейших трудностей я предпочитаю использовать чанкованный перевод.

изменение кода:

func (w *writeReplacer) WriteHeader(statusCode int) {
    w.Header().Del("Content-length")
    w.Header().Set("Transfer-Encoding", "chunked")
    w.ResponseWriter.WriteHeader(statusCode)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...