Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。

Home Page:https://muyiy.cn/question/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

第 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 生成方式可能不一样。

commented

Etag 是一个文件变换就要重新生成的一个值,如果用hash来计算达不到效率
不过http也没有明确指出它的计算方式吧
不过在nginx里面,是由Last-Modified和content-length的十六进制组合而成
这样想来是个Etag加强版本的Last-Modified,毕竟Last-Modified是个时间戳,只能精确到秒