Go HTTP客户端添加了服务不支持的分块编码
GoHTTP客户端正在向我的客户端请求添加一个“分块”传输编码字段。不幸的是,我连接的服务不支持这一点,它返回时出错 有没有办法禁用此功能 这是我的请求代码: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
// 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!很高兴你明白了