检测 gzip 编码以手动解压缩响应,但缺少 'Content-Encoding' header
Detect gzip encoding to manually decompress response, but 'Content-Encoding' header missing
我正在使用 'Go' 中的 net/http
库来发出 HTTP GET
请求。在响应中,我得到 12 headers。但是当我 运行 通过邮递员进行完全相同的查询时,我得到 16 headers。其中一个缺失的是 'Content-Encoding'。我知道这一定是一个 CORS 问题。
但是由于我没有在我的请求中设置 header Accept-Encoding: gzip
,而且我仍然得到 gzip 编码作为响应,Go 传输不是 automatically decompressing the response for me。所以,我需要能够手动检测编码然后解压缩。但是,我无法检测到响应中是否缺少 'Content-Encoding' header。
这是我尝试执行此操作的代码:
func calcDistanceAndDurationWithUberApi(originLat float64, originLon float64, destinationLat float64, destinationLon float64) (float64, float64, error) {
endpoint := "https://api.uber.com/v1.2/estimates/price"
parameters := fmt.Sprintf("?start_latitude=%v&start_longitude=%v&end_latitude=%v&end_longitude=%v", originLat, originLon, destinationLat, destinationLon)
req, err := http.NewRequest("GET", endpoint + parameters, nil)
if err != nil {
return 0, 0, err
}
req.Header.Add("Authorization", "Token " + getUberApiKey())
req.Header.Add("Accept-Language", "en_US")
req.Header.Add("Content-Type", "application/json")
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
return 0, 0, err
}
if resp.StatusCode != 200 {
return 0, 0, errors.NotFound("Response: %v", resp.StatusCode)
}
defer resp.Body.Close()
pretty.Println("- REQUEST: ")
pretty.Println(req)
// Check if server sent gzipped response. Decompress if yes.
var respReader io.ReadCloser
switch resp.Header.Get("Content-Encoding") {
case "gzip":
fmt.Println("Content-Encoding is gzip")
respReader, err = gzip.NewReader(resp.Body)
defer respReader.Close()
default:
fmt.Println("Content-Encoding is Not gzip")
respReader = resp.Body
}
pretty.Println("- RESPONSE HEADER: ")
pretty.Println(resp.Header)
pretty.Println("- RESPONSE BODY: ")
pretty.Println(respReader)
return 0, 0, nil
}
响应状态为“200 OK”。这是输出(响应):
- RESPONSE HEADER:
http.Header{
"Content-Language": {"en"},
"Cache-Control": {"max-age=0"},
"X-Uber-App": {"uberex-nonsandbox", "optimus"},
"Strict-Transport-Security": {"max-age=604800", "max-age=2592000"},
"X-Content-Type-Options": {"nosniff"},
"Date": {"Fri, 19 May 2017 07:52:17 GMT"},
"Content-Geo-System": {"wgs-84"},
"Connection": {"keep-alive"},
"X-Frame-Options": {"SAMEORIGIN"},
"X-Xss-Protection": {"1; mode=block"},
"Server": {"nginx"},
"Content-Type": {"application/json"},
}
- RESPONSE BODY:
&http.gzipReader{
body: &http.bodyEOFSignal{
body: &http.body{
src: &internal.chunkedReader{
r: &bufio.Reader{
buf: {0x48, 0x54, .......... }
我屈服于 uber api 的固执,并添加了另一个请求 header,req.Header.Add("Accept-Encoding", "gzip")
。
现在我收到回复 header "Content-Encoding": "gzip"
,虽然我仍然收到无法辨认的回复 body,但这超出了这个问题的范围。
如果您不禁用压缩 [1],并且您不使用 Accept-Encoding: gzip
手动请求压缩,则会使用我所说的“自动模式”。在自动模式下,Go 自动添加 Accept-Encoding: gzip
,然后如果服务器响应 Content-Encoding: gzip
,Go 将响应 body 包装在 Gzip reader, 中并删除 Content-Encoding 和 Content-Length 响应 headers [2]。我不同意这种做法,因为最终用户基本上被骗了真正的反应是什么。将此与 cURL 进行对比,无论您做什么,它都会为您提供纯粹的响应:
PS C:\> curl -v --compressed https://github.com/manifest.json
< content-encoding: gzip
< content-length: 345
为了解决这个问题,我为 http.Transport
写了一个包装器:
package mech
import (
"compress/gzip"
"io"
"net/http"
"strings"
)
type Transport struct { http.Transport }
func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if !t.DisableCompression {
req.Header.Set("Accept-Encoding", "gzip")
}
res, err := t.Transport.RoundTrip(req)
if err != nil {
return nil, err
}
if strings.EqualFold(res.Header.Get("Content-Encoding"), "gzip") {
gz, err := gzip.NewReader(res.Body)
if err != nil {
return nil, err
}
res.Body = readCloser{gz, res.Body}
}
return res, nil
}
type readCloser struct {
io.Reader
io.Closer
}
我正在使用 'Go' 中的 net/http
库来发出 HTTP GET
请求。在响应中,我得到 12 headers。但是当我 运行 通过邮递员进行完全相同的查询时,我得到 16 headers。其中一个缺失的是 'Content-Encoding'。我知道这一定是一个 CORS 问题。
但是由于我没有在我的请求中设置 header Accept-Encoding: gzip
,而且我仍然得到 gzip 编码作为响应,Go 传输不是 automatically decompressing the response for me。所以,我需要能够手动检测编码然后解压缩。但是,我无法检测到响应中是否缺少 'Content-Encoding' header。
这是我尝试执行此操作的代码:
func calcDistanceAndDurationWithUberApi(originLat float64, originLon float64, destinationLat float64, destinationLon float64) (float64, float64, error) {
endpoint := "https://api.uber.com/v1.2/estimates/price"
parameters := fmt.Sprintf("?start_latitude=%v&start_longitude=%v&end_latitude=%v&end_longitude=%v", originLat, originLon, destinationLat, destinationLon)
req, err := http.NewRequest("GET", endpoint + parameters, nil)
if err != nil {
return 0, 0, err
}
req.Header.Add("Authorization", "Token " + getUberApiKey())
req.Header.Add("Accept-Language", "en_US")
req.Header.Add("Content-Type", "application/json")
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
return 0, 0, err
}
if resp.StatusCode != 200 {
return 0, 0, errors.NotFound("Response: %v", resp.StatusCode)
}
defer resp.Body.Close()
pretty.Println("- REQUEST: ")
pretty.Println(req)
// Check if server sent gzipped response. Decompress if yes.
var respReader io.ReadCloser
switch resp.Header.Get("Content-Encoding") {
case "gzip":
fmt.Println("Content-Encoding is gzip")
respReader, err = gzip.NewReader(resp.Body)
defer respReader.Close()
default:
fmt.Println("Content-Encoding is Not gzip")
respReader = resp.Body
}
pretty.Println("- RESPONSE HEADER: ")
pretty.Println(resp.Header)
pretty.Println("- RESPONSE BODY: ")
pretty.Println(respReader)
return 0, 0, nil
}
响应状态为“200 OK”。这是输出(响应):
- RESPONSE HEADER:
http.Header{
"Content-Language": {"en"},
"Cache-Control": {"max-age=0"},
"X-Uber-App": {"uberex-nonsandbox", "optimus"},
"Strict-Transport-Security": {"max-age=604800", "max-age=2592000"},
"X-Content-Type-Options": {"nosniff"},
"Date": {"Fri, 19 May 2017 07:52:17 GMT"},
"Content-Geo-System": {"wgs-84"},
"Connection": {"keep-alive"},
"X-Frame-Options": {"SAMEORIGIN"},
"X-Xss-Protection": {"1; mode=block"},
"Server": {"nginx"},
"Content-Type": {"application/json"},
}
- RESPONSE BODY:
&http.gzipReader{
body: &http.bodyEOFSignal{
body: &http.body{
src: &internal.chunkedReader{
r: &bufio.Reader{
buf: {0x48, 0x54, .......... }
我屈服于 uber api 的固执,并添加了另一个请求 header,req.Header.Add("Accept-Encoding", "gzip")
。
现在我收到回复 header "Content-Encoding": "gzip"
,虽然我仍然收到无法辨认的回复 body,但这超出了这个问题的范围。
如果您不禁用压缩 [1],并且您不使用 Accept-Encoding: gzip
手动请求压缩,则会使用我所说的“自动模式”。在自动模式下,Go 自动添加 Accept-Encoding: gzip
,然后如果服务器响应 Content-Encoding: gzip
,Go 将响应 body 包装在 Gzip reader, 中并删除 Content-Encoding 和 Content-Length 响应 headers [2]。我不同意这种做法,因为最终用户基本上被骗了真正的反应是什么。将此与 cURL 进行对比,无论您做什么,它都会为您提供纯粹的响应:
PS C:\> curl -v --compressed https://github.com/manifest.json
< content-encoding: gzip
< content-length: 345
为了解决这个问题,我为 http.Transport
写了一个包装器:
package mech
import (
"compress/gzip"
"io"
"net/http"
"strings"
)
type Transport struct { http.Transport }
func (t Transport) RoundTrip(req *http.Request) (*http.Response, error) {
if !t.DisableCompression {
req.Header.Set("Accept-Encoding", "gzip")
}
res, err := t.Transport.RoundTrip(req)
if err != nil {
return nil, err
}
if strings.EqualFold(res.Header.Get("Content-Encoding"), "gzip") {
gz, err := gzip.NewReader(res.Body)
if err != nil {
return nil, err
}
res.Body = readCloser{gz, res.Body}
}
return res, nil
}
type readCloser struct {
io.Reader
io.Closer
}