HTTP ETag 和 HTTP 重定向

Eri*_*ban 4 etag http go

我有一个网络服务器,它发出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
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,它可以正常工作。

我只是存储和发送GET请求的 ETag 。虽然将它们发送给其他请求是有效的,但它目前不在我的用例中,所以我不打扰它。通过将url.URL对象映射到字符串来存储 ETag 。

我的问题是这个。我请求“ http://foo.com/bar.html ”。服务器将我使用302 FoundLocation标题重定向到“ http://foo.com/qux.html ”。然后我请求“ http://foo.com/qux.html ”并得到200 OK一个ETag标题。

ETag将上次响应的标头与哪个 URL 相关联?

可以在302 Found本身包括ETag头?

Jep*_*hir 5

一个ETag的与当前请求的“选择的表示”相关联。302 Found响应的选定表示“通常包含一个简短的超文本注释,其中包含指向不同 URI 的超链接。” 因此,如果 302 响应包含 ETag,则 ETag 与该超文本相关联。

但是,如果您在对以重定向响应的资源的请求中包含 If-None-Match(或其他前提条件),则服务器将忽略该前提条件。根据RFC 7232 的第 5 节(我的重点):

如果服务器对没有这些条件的相同请求的响应将是 2xx(成功)或 412(前提条件失败)以外的状态代码,则它必须忽略所有接收到的前提条件。换句话说,重定向和失败优先于条件请求中的先决条件的评估

因此,虽然 302 响应可以包含 ETag,但它没有用,因为服务器可能不会在对该资源的进一步请求中使用它。