HTTP ETags和HTTP重定向

huangapple go评论79阅读模式
英文:

HTTP ETags and HTTP Redirects

问题

我有一个发出响应的Web服务器,并检查客户端的If-None-Match头部,如果存在的话,会在响应中添加ETag头部。在这种情况下,客户端不是一个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"

    // 不要在非GET请求上尝试使用ETags
    if req.Method != "GET" {
        return hc.Client.Do(req)
    }

    // 检查现有的ETag
    etag, ok := hc.etags[*req.URL]
    if ok { // 如果存在ETag,则发送它
        if req.Header == nil {
            req.Header = http.Header{}
        }
        req.Header.Add(ETAG_CLIENT_HEADER, etag)
    }

    // 执行响应
    response, err := hc.Client.Do(req)
    // 如果响应正常
    if err == nil {

        if hc.etags == nil {
            hc.etags = make(map[url.URL]string)
        }

        // 检查服务器的ETAG,如果存在则存储它
        etag = response.Header.Get(ETAG_SERVER_HEADER)
        if len(etag) != 0 {
            hc.etags[*req.URL] = etag
        }
    }

    return response, err
}

目前它没有问题。

我只存储和发送GET请求的ETag。虽然对于其他请求也可以发送ETag,但在我的用例中目前不需要,所以我没有处理它。ETag是通过将url.URL对象映射到字符串来存储的。

我的问题是这样的。我请求"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头部?

英文:

I have a webserver that issues the ETag header on responses and checks the If-None-Match header from the client, if present. The client in this case, is not a web browser but an extension of go's builtin net/http http.Client type.

Here is my code

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
}

It is working without issue as of present.

I am only storing and sending the ETag for GET requests. While it is valid to send them for other requests, it is not in my use case as of current so I'm not bothering with it. The ETags are stored by mapping the url.URL object to a string.

My question is this. I request "http://foo.com/bar.html". The server redirects me using 302 Found and the Location header to "http://foo.com/qux.html". I then request "http://foo.com/qux.html" and get a 200 OK along with an ETag header.

With what URL do I associate the ETag header from the last response?

Could the 302 Found itself include an ETag header?

答案1

得分: 5

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

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

> 如果服务器对同一请求的响应不满足这些条件,其状态码不是2xx(成功)或412(前提条件失败),则服务器必须忽略所有接收到的前提条件。换句话说,在条件请求中,重定向和失败优先于前提条件的评估

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

英文:

An ETag is associated with the "selected representation" of the current request. The selected representation for a 302 Found response "usually contains a short hypertext note with a hyperlink to the different URI(s)." Therefore, if a 302 response contains an ETag, the ETag is associated with that hypertext.

However, if you include an If-None-Match (or other precondition) in a request to a resource that responds with a redirect, the server will ignore the precondition. According to Section 5 of RFC 7232 (my emphasis):

> A server MUST ignore all received preconditions if its response to the same request without those conditions would have been a status code other than a 2xx (Successful) or 412 (Precondition Failed). In other words, redirects and failures take precedence over the evaluation of preconditions in conditional requests.

Thus, while a 302 response can contain an ETag, it is not useful because the server may not use it in further requests to that resource.

答案2

得分: 3

如您在/src/pkg/net/http/client.go的第266行中所见,请求-响应循环将持续进行,直到以下情况之一:

  • http.Client的重定向检查器(CheckRedirect字段)返回错误
  • 收到的响应不是重定向(根据shouldRedirectGet

在循环过程中,先前的响应将被丢弃,client.Do返回的响应头是最后一个响应的头。

这意味着您应该将ETag与您示例中的qux.html关联起来。

> 302 Found本身是否可以包含ETag头?

是的,它可以包含,但由于它是一个重定向,客户端将跟随它并从目标URL获取一组新的响应头。

英文:

As you can see in /src/pkg/net/http/client.go on line 266 the request-response cycle will continue until either or:

  • The http.Client's redirect checker (CheckRedirect field) returns an error
  • The response received is not a redirect (according to shouldRedirectGet)

During the cycle , previous responses will be discarded and the headers the response that client.Do returns are those of the last response.

This means that you should associate the ETag with qux.html in your example.

> Could the 302 Found itself include an ETag header?

Yes it could but since it's a redirect, the client will follow it and acquire a new set of response headers from the target URL.

huangapple
  • 本文由 发表于 2014年4月11日 21:32:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/23014106.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定