go net/http: NewFileTransport does not populate Response.Request on redirect

eblbsuwk  于 4个月前  发布在  Go
关注(0)|答案(1)|浏览(30)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.17.8 darwin/amd64

这个问题在最新版本的发布中是否重现?

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env

GO111MODULE=""

GOARCH="amd64"

GOBIN=""

GOCACHE="/Users/aron/Library/Caches/go-build"

GOENV="/Users/aron/Library/Application Support/go/env"

GOEXE=""

GOEXPERIMENT=""

GOFLAGS=""

GOHOSTARCH="amd64"

GOHOSTOS="darwin"

GOINSECURE=""

GOMODCACHE="/Users/aron/go/pkg/mod"

GONOPROXY=""

GONOSUMDB=""

GOOS="darwin"

GOPATH="/Users/aron/go"

GOPRIVATE=""

GOPROXY=" [https://proxy.golang.org,direct](https://proxy.golang.org,direct) "

GOROOT="/usr/local/go"

GOSUMDB="sum.golang.org"

GOTMPDIR=""

GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"

GOVCS=""

GOVERSION="go1.17.8"

GCCGO="gccgo"

AR="ar"

CC="clang"

CXX="clang++"

CGO_ENABLED="1"

GOMOD="/dev/null"

CGO_CFLAGS="-g -O2"

CGO_CPPFLAGS=""

CGO_CXXFLAGS="-g -O2"

CGO_FFLAGS="-g -O2"

CGO_LDFLAGS="-g -O2"

PKG_CONFIG="pkg-config"

GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8j/pt4fjhkj11d3xd9344pdspmh0000gn/T/go-build2963024848=/tmp/go-build -gno-record-gcc-switches -fno-common"

你做了什么?

http.NewFileTransport 创建了一个传输,其中 RoundTrip 在重定向时没有填充其 Request 字段。
给定以下Go程序:

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)
func main() {
	transport := &http.Transport{}
	transport.RegisterProtocol("file", http.NewFileTransport(http.Dir("./www")))
	client := &http.Client{
		Transport: transport,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			fmt.Printf("redirect-check: %s\n", req.URL)
			// we do our own redirect processing.
			return nil
		},
	}
	targetURL := "file:///sub"
	fmt.Printf("target url: %s\n", targetURL)
	resp, err := client.Get(targetURL)
	if err != nil {
		fmt.Printf("client error: %s\n")
		os.Exit(1)
	}

	if resp.Request != nil {
		fmt.Printf("request url: %s\n", resp.Request.URL)
	} else {
		fmt.Printf("no response request\n")
	}

	fmt.Printf("body-start\n")
	io.Copy(os.Stdout, resp.Body)
	fmt.Printf("body-end\n")
	
}

使用本地目录结构:

www/
    sub/
        index.html

你期望看到什么?

我期望程序打印:

target url: file:///sub
redirect-check: file:///sub/
request url: file:///sub/
body-start
<html><body>sub</body></html>
body-end

request url 打印行表示客户端返回的 http.Response 字段已填充,这允许调用者了解沿着 (本地)重定向链请求的最终URL。

你看到了什么?

使用Go 1.17.8,程序打印:

$ go run main.go
target url: file:///sub
redirect-check: file:///sub/
no response request
body-start
<html><body>sub</body></html>
body-end

no response redirect 表示客户端返回的 http.Response 字段为空,这与使用非文件传输时的行为不同。

ycggw6v2

ycggw6v21#

作为解决方法,使用 CheckRedirect 记录最近的请求;例如:

var lastCheckedRequest *http.Request
	client := &http.Client{
		Transport: transport,
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			lastCheckedRequest = req
			return nil
		},
	}

然后可以使用类似以下方式确定最终目标URL:

// targetURL is where we landed after any redirects.
	targetURL := initialURL
	if r.Request != nil {
		targetURL = r.Request.URL.String()
	} else if lastCheckedRequest != nil {
		targetURL = lastCheckedRequest.URL.String()
	}

在每次调用客户端之间,需要重置 lastCheckedRequest。这种方法不处理并发客户端使用。

相关问题