我有一个Web服务器,它在响应中发出 ETag
标头,并检查客户端的 If-None-Match
标头(如果存在) . 在这种情况下,客户端不是Web浏览器,而是go的内置 net/http
http.Client
类型的扩展 .
这是我的代码
package util
import "net/http"
import "net/url"
type HttpClient struct {
http.Client
etags map[url.URL]string
}
func (hc *HttpClient) Do(req *http.Request) (*http.Response, error) {
const ETAG_SERVER_HEADER = "ETag"
const ETAG_CLIENT_HEADER = "If-None-Match"
//Do not attempt to use ETags on non-GET requests
if req.Method != "GET" {
return hc.Client.Do(req)
}
//Check for an existing etag
etag, ok := hc.etags[*req.URL]
if ok { //If an ETag is present, send it along
if req.Header == nil {
req.Header = http.Header{}
}
req.Header.Add(ETAG_CLIENT_HEADER, etag)
}
//Do the response
response, err := hc.Client.Do(req)
//If the response is ok
if err == nil {
if hc.etags == nil {
hc.etags = make(map[url.URL]string)
}
//Check for an ETAG from the server, store it if present
etag = response.Header.Get(ETAG_SERVER_HEADER)
if len(etag) != 0 {
hc.etags[*req.URL] = etag
}
}
return response, err
}
它目前没有问题 .
我只是为 GET
请求存储和发送ETag . 虽然将它们发送给其他请求是有效的,但它不是我当前的用例,所以我不打扰它 . 通过将 url.URL
对象映射到字符串来存储ETag .
我的问题是这个 . 我要求“http://foo.com/bar.html” . 服务器使用 302 Found
和 Location
标头将我重定向到“http://foo.com/qux.html ". I then request " http://foo.com/qux.html”并获得 200 OK
以及 ETag
标头 .
使用什么URL关联上一个响应中的 ETag
标头?
302 Found
本身可以包含一个 ETag
Headers 吗?
2 回答
ETag与当前请求的"selected representation"关联 . 所选的302 Found响应表示"usually contains a short hypertext note with a hyperlink to the different URI(s)."因此,如果302响应包含ETag,则ETag与该超文本相关联 .
但是,如果在对具有重定向响应的资源的请求中包含ETag,则服务器将忽略ETag . 根据Section 5 of RFC 7232(我的重点):
因此,虽然302响应可以包含ETag,但它没有用,因为服务器可能不会在对该资源的进一步请求中使用它 .
正如您在第266行的/src/pkg/net/http/client.go中所见,请求 - 响应周期将持续到以下任一或:
http.Client
的重定向检查程序(CheckRedirect
字段)返回错误收到的回复不是重定向(根据shouldRedirectGet)
在循环期间,先前的响应将被丢弃,并且
client.Do
返回的响应的标头是最后一个响应的响应 .这意味着您应该在示例中将
ETag
与qux.html
关联 .是的,它可以,但由于它是重定向,客户端将遵循它并从目标URL获取一组新的响应头 .