第 157 题:浏览器缓存 ETag 里的值是怎么生成的
yygmind opened this issue · comments
Etag是服务器响应请求时,返回当前资源文件的一个唯一标识(由服务器生成)。
语法:
ETag: W/"<etag_value>"
ETag: "<etag_value>"
'W/'(大小写敏感)
表示使用弱验证器,可选。 弱验证器很容易生成,但不利于比较。 强验证器是比较的理想选择,但很难有效地生成。 相同资源的两个弱Etag值可能语义等同,但不是每个字节都相同。
"<etag_value>"
实体标签唯一地表示所请求的资源。 它们是位于双引号之间的ASCII字符串(如“675af34563dc-tr34”)。 没有明确指定生成ETag值的方法。 通常,使用内容的散列,最后修改时间戳的哈希值,或简单地使用版本号。 例如,MDN使用wiki内容的十六进制数字的哈希值。
1. Nginx 的 ETag 生成方式:http://lxr.nginx.org/source/src/http/ngx_http_core_module.c
注意:行1608、1609
1581 ngx_int_t
1582 ngx_http_set_etag(ngx_http_request_t *r)
1583 {
1584 ngx_table_elt_t *etag;
1585 ngx_http_core_loc_conf_t *clcf;
1586
1587 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1588
1589 if (!clcf->etag) {
1590 return NGX_OK;
1591 }
1592
1593 etag = ngx_list_push(&r->headers_out.headers);
1594 if (etag == NULL) {
1595 return NGX_ERROR;
1596 }
1597
1598 etag->hash = 1;
1599 ngx_str_set(&etag->key, "ETag");
1600
1601 etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3);
1602 if (etag->value.data == NULL) {
1603 etag->hash = 0;
1604 return NGX_ERROR;
1605 }
1606
1607 etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
1608 r->headers_out.last_modified_time,
1609 r->headers_out.content_length_n)
1610 - etag->value.data;
1611
1612 r->headers_out.etag = etag;
1613
1614 return NGX_OK;
1615 }
2. Apache 的生成方式 http://httpd.apache.org/docs/2.2/mod/core.html#fileetag
关于配置里提到的 inode,不知道的可以参考:http://www.ruanyifeng.com/blog/2011/12/inode.html
不同 Web 服务器或者 CDN 的 ETag 生成方式可能不一样。
Etag 是一个文件变换就要重新生成的一个值,如果用hash来计算达不到效率
不过http也没有明确指出它的计算方式吧
不过在nginx里面,是由Last-Modified和content-length的十六进制组合而成
这样想来是个Etag加强版本的Last-Modified,毕竟Last-Modified是个时间戳,只能精确到秒