Spring MVC 响应标头:ETag 对 GET 请求有双引号,但对 PUT 请求没有

Ton*_*ony 5 etag spring get put spring-mvc

我们在我们的服务中将 Spring MVC 从 4.0 升级到 4.3。它导致“GET”方法的响应标头中的 ETag 格式更改。进行“GET”调用的客户端将在响应标头中获得带有双引号的 ETag。以前响应头中的 ETag 没有“GET”方法的双引号。

例如:

Now: etag ?"TVMzTWFpbmxpbmVEZXZvLTI5ODIxMQ" 
Previously: etag ?TVMzTWFpbmxpbmVEZXZvLTI5ODIxMQ
Run Code Online (Sandbox Code Playgroud)

"PUT" 请求的响应在 Headers 中的 ETag 周围没有双引号,就像以前一样。

任何人有任何想法为什么?

Nao*_*aoj 4

在 Spring 4.2.x 之前,没有对 ETag 标头的管理。从那时起,它就被引入到HttpEntityMethodProcessor中。该类随着时间的推移而不断发展,ETag 标头的管理遵循RFC(或足够接近)。

\n

正如您在此提交中看到的,Spring 团队修复了其管理问题:

\n
\n

修复响应中丢失的 ETag/LastModified 标头

\n
\n
\n

在此提交之前,将HttpEntityMethodProcessor避免在调用处理条件请求之前写入 ETag/Last-Modified 响应标头ServletWebRequest。这样做是为了避免由于标头已写入底层 servlet 响应而导致重复的响应标头值。

\n
\n
\n

这对于 GET/HEAD 请求仍然是必要的,因为对于这些情况,这是正确处理的ServletWebRequest。但是\nHttpEntityMethodProcessor不应该对PUT/PATCH/POST 响应做出该决定,因为开发人员有意添加响应标头,并且应该控制情况\xe2\x80\x94,而\n 在这些ServletWebRequest情况下不会写入这些标头。

\n
\n

修改后的代码的相关部分在这里

\n

所以基本上,当您手动添加ETag 标头时,如果GETHEAD方法的状态为200 ,框架会删除它,然后重新创建它。这就是为什么 PUT没有双引号。

\n

在 HttpEntityMethodProcessor 中:

\n
    if (inputMessage.getMethod() == HttpMethod.GET || inputMessage.getMethod() == HttpMethod.HEAD) {\n        responseHeaders.remove(HttpHeaders.ETAG);\n        responseHeaders.remove(HttpHeaders.LAST_MODIFIED);\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

然后在ServletWebRequest中:

\n
private String padEtagIfNecessary(String etag) {\n    if (!StringUtils.hasLength(etag)) {\n        return etag;\n    }\n    if ((etag.startsWith("\\"") || etag.startsWith("W/\\"")) && etag.endsWith("\\"")) {\n        return etag;\n    }\n    return "\\"" + etag + "\\"";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,这符合RFC 第 2.4 章

\n
\n

2.4. 何时使用实体标签和上次修改日期

\n
\n
\n

在对 GET 或 HEAD 的 200(OK)响应中,源服务器:

\n
\n
\n

o 应发送实体标签验证器,除非无法生成\n。

\n
\n
\n

o 如果\n性能考虑支持使用弱实体标签,或者\n如果发送强实体标签不可行,则可以发送弱实体标签而不是强实体标签。

\n
\n
\n

o 如果可以发送一个 Last-Modified 值,则应该发送该值。

\n
\n
\n

换句话说,源服务器的首选行为是在成功响应检索请求时发送强实体标记和上次修改值。

\n
\n

但我发现它不向后兼容,并且破坏了开发人员在这些版本之前可以使用的内容,并且无法跳过/覆盖他们所做的事情。

\n

这是来自 MDN 的 ETag描述(更清晰)。

\n

希望对理解有所帮助。

\n