Go HTTP客户端添加了服务不支持的分块编码

Go HTTP客户端添加了服务不支持的分块编码,go,Go,GoHTTP客户端正在向我的客户端请求添加一个“分块”传输编码字段。不幸的是,我连接的服务不支持这一点,它返回时出错 有没有办法禁用此功能 这是我的请求代码: // DoHTTPRequest Do a full HTTP Client Request, with timeout func DoHTTPRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (*ht

GoHTTP客户端正在向我的客户端请求添加一个“分块”传输编码字段。不幸的是,我连接的服务不支持这一点,它返回时出错

有没有办法禁用此功能

这是我的请求代码:

// DoHTTPRequest Do a full HTTP Client Request, with timeout
func DoHTTPRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (*http.Response, error) {

    // Create the request
    req, err := http.NewRequest(method, url, body)
    if err != nil {
        return nil, err
    }

    // Add headers
    for k, v := range headers {
        req.Header.Set(k, v)
    }

    client := &http.Client{
        Timeout: timeout,
    }

    return client.Do(req)
}
基本上,我希望这个标题下降。该客户机正在与S3通信,S3对发送的报头相当敏感

我得到这个错误:

A header you provided implies functionality that is not implemented

transferncode
是直接位于请求结构上的字段。如果显式设置,则不会覆盖它

req.transferncode=[]字符串{“标识”}


Transferncode
是直接位于请求结构上的字段。如果显式设置,则不会覆盖它

req.transferncode=[]字符串{“标识”}


这样设置传输编码头使其不使用分块:

req.TransferEncoding = []string{"identity"}
然而,http客户端源代码给出了在我的例子中选择chunked的原因。具体来说,我使用“PUT”作为方法,没有指定内容长度。所以我只需要设置req.ContentLength

但是,您可以看到我的
DoHTTPRequest
wrapper函数不知道设置它有多大。我假设设置标题会使它最初工作。好吧,设置标题不起作用。您可以在决定是否使用分块编码的源代码中看到原因

// shouldSendChunkedRequestBody reports whether we should try to send a
// chunked request body to the server. In particular, the case we really
// want to prevent is sending a GET or other typically-bodyless request to a
// server with a chunked body when the body has zero bytes, since GETs with
// bodies (while acceptable according to specs), even zero-byte chunked
// bodies, are approximately never seen in the wild and confuse most
// servers. See Issue 18257, as one example.
//
// The only reason we'd send such a request is if the user set the Body to a
// non-nil value (say, ioutil.NopCloser(bytes.NewReader(nil))) and didn't
// set ContentLength, or NewRequest set it to -1 (unknown), so then we assume
// there's bytes to send.
//
// This code tries to read a byte from the Request.Body in such cases to see
// whether the body actually has content (super rare) or is actually just
// a non-nil content-less ReadCloser (the more common case). In that more
// common case, we act as if their Body were nil instead, and don't send
// a body.
func (t *transferWriter) shouldSendChunkedRequestBody() bool {
    // Note that t.ContentLength is the corrected content length
    // from rr.outgoingLength, so 0 actually means zero, not unknown.
    if t.ContentLength >= 0 || t.Body == nil { // redundant checks; caller did them
        return false
    }
    if requestMethodUsuallyLacksBody(t.Method) {
        // Only probe the Request.Body for GET/HEAD/DELETE/etc
        // requests, because it's only those types of requests
        // that confuse servers.
        t.probeRequestBody() // adjusts t.Body, t.ContentLength
        return t.Body != nil
    }
    // For all other request types (PUT, POST, PATCH, or anything
    // made-up we've never heard of), assume it's normal and the server
    // can deal with a chunked request body. Maybe we'll adjust this
    // later.
    return true
}
因此,我的解决方案很简单:

// DoHTTPRequest Do a full HTTP Client Request, with timeout
func DoHTTPRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (*http.Response, error) {

    // Create the request
    req, err := http.NewRequest(method, url, body)
    if err != nil {
        return nil, err
    }

    // Add headers
    for k, v := range headers {
        req.Header.Set(k, v)
        // Set the Content Length correctly if specified.
        if strings.EqualFold(k, "Content-Length") {
            length, err := strconv.Atoi(v)
            if err != nil {
               return nil, fmt.Errorf("Bad Content-Length header")
            }
            req.ContentLength = int64(length)
        }
    }

    client := &http.Client{
        Timeout:   timeout,
        Transport: &loghttp.Transport{},
    }

    return client.Do(req)
}

只要内容长度正确,就满足S3的要求。我不需要将TransferEncode设置为identity。

这样设置TransferEncoding头,使其不使用chunked:

req.TransferEncoding = []string{"identity"}
然而,http客户端源代码给出了在我的例子中选择chunked的原因。具体来说,我使用“PUT”作为方法,没有指定内容长度。所以我只需要设置req.ContentLength

但是,您可以看到我的
DoHTTPRequest
wrapper函数不知道设置它有多大。我假设设置标题会使它最初工作。好吧,设置标题不起作用。您可以在决定是否使用分块编码的源代码中看到原因

// shouldSendChunkedRequestBody reports whether we should try to send a
// chunked request body to the server. In particular, the case we really
// want to prevent is sending a GET or other typically-bodyless request to a
// server with a chunked body when the body has zero bytes, since GETs with
// bodies (while acceptable according to specs), even zero-byte chunked
// bodies, are approximately never seen in the wild and confuse most
// servers. See Issue 18257, as one example.
//
// The only reason we'd send such a request is if the user set the Body to a
// non-nil value (say, ioutil.NopCloser(bytes.NewReader(nil))) and didn't
// set ContentLength, or NewRequest set it to -1 (unknown), so then we assume
// there's bytes to send.
//
// This code tries to read a byte from the Request.Body in such cases to see
// whether the body actually has content (super rare) or is actually just
// a non-nil content-less ReadCloser (the more common case). In that more
// common case, we act as if their Body were nil instead, and don't send
// a body.
func (t *transferWriter) shouldSendChunkedRequestBody() bool {
    // Note that t.ContentLength is the corrected content length
    // from rr.outgoingLength, so 0 actually means zero, not unknown.
    if t.ContentLength >= 0 || t.Body == nil { // redundant checks; caller did them
        return false
    }
    if requestMethodUsuallyLacksBody(t.Method) {
        // Only probe the Request.Body for GET/HEAD/DELETE/etc
        // requests, because it's only those types of requests
        // that confuse servers.
        t.probeRequestBody() // adjusts t.Body, t.ContentLength
        return t.Body != nil
    }
    // For all other request types (PUT, POST, PATCH, or anything
    // made-up we've never heard of), assume it's normal and the server
    // can deal with a chunked request body. Maybe we'll adjust this
    // later.
    return true
}
因此,我的解决方案很简单:

// DoHTTPRequest Do a full HTTP Client Request, with timeout
func DoHTTPRequest(method, url string, body io.Reader, headers map[string]string, timeout time.Duration) (*http.Response, error) {

    // Create the request
    req, err := http.NewRequest(method, url, body)
    if err != nil {
        return nil, err
    }

    // Add headers
    for k, v := range headers {
        req.Header.Set(k, v)
        // Set the Content Length correctly if specified.
        if strings.EqualFold(k, "Content-Length") {
            length, err := strconv.Atoi(v)
            if err != nil {
               return nil, fmt.Errorf("Bad Content-Length header")
            }
            req.ContentLength = int64(length)
        }
    }

    client := &http.Client{
        Timeout:   timeout,
        Transport: &loghttp.Transport{},
    }

    return client.Do(req)
}

只要内容长度正确,就满足S3的要求。我不需要将Transferncode设置为identity。

您是否尝试将
'Transfer-Encoding'
头显式设置为您使用的服务允许的其他内容
gzip
或者
identity
也许吧?我刚刚试过identity。它会覆盖它,如果使用os.file作为io.Reader,会导致它使用chunked吗?你能内联内容吗?如果是多行的话,它可能会把新行分块。或者您也可以尝试设置
内容长度
,正如前面提到的那样。之后甚至可能会明确删除
'Transfer-Encoding'
头。值得一提的是,go似乎遵循了这里的规范:所有HTTP/1.1应用程序都必须能够接收和解码“分块的”传输编码您是否尝试将
'transfer-Encoding'
头显式设置为您正在使用的服务允许的其他内容
gzip
或者
identity
也许吧?我刚刚试过identity。它会覆盖它,如果使用os.file作为io.Reader,会导致它使用chunked吗?你能内联内容吗?如果是多行的话,它可能会把新行分块。或者您也可以尝试设置
内容长度
,正如前面提到的那样。之后甚至可能会明确删除
'Transfer-Encoding'
头。值得一提的是,go似乎遵循了这里的规范:所有HTTP/1.1应用程序都必须能够接收和解码实际工作的“分块”传输编码。现在我有另一个问题。。。不幸!事实上,我不需要这个。只需设置req.ContentLength.Nice!很高兴你发现它确实有效。现在我有另一个问题。。。不幸!事实上,我不需要这个。只需设置req.ContentLength.Nice!很高兴你明白了