{"id":15683,"date":"2026-11-09T08:05:00","date_gmt":"2026-11-09T07:05:00","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/?p=15683"},"modified":"2026-10-26T13:14:31","modified_gmt":"2026-10-26T12:14:31","slug":"the-question-that-saves-nothing-etag-last-modified-and-the-missing-304","status":"publish","type":"post","link":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/","title":{"rendered":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304"},"content":{"rendered":"<p>A cached response is fresh while the cache rules permit reuse without asking the server. Such a response can avoid a network request. Once checking becomes necessary, a validator can avoid transferring the body again: a matching conditional GET can receive <code>304 Not Modified<\/code>. That still costs a request and processing time. A cache without validators can therefore remain useful while a stored response is reusable.<\/p>\n<p>A historical run from 5 September 2026 covered twenty starting URLs. Eleven recorded responses contained neither an ETag nor Last-Modified. This describes those responses, not an inability of eleven entire websites to support conditional requests.<\/p>\n<figure class=\"lw-diagram\"><img decoding=\"async\" src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/diagrams\/reval-reviewed-en-20261025.png\" width=\"1120\" height=\"580\" loading=\"lazy\" alt=\"Historical response headers and interpretation: 304 avoids the body, while 200 alone does not prove a change or a defect.\"><figcaption>Historical response headers and interpretation: 304 avoids the body, while 200 alone does not prove a change or a defect.<\/figcaption><\/figure>\n<h2>Two validators, different guarantees<\/h2>\n<p><code>Last-Modified<\/code> describes the last modification time with one-second precision. The corresponding request field is <code>If-Modified-Since<\/code>. Multiple changes within a second can exceed that precision.<\/p>\n<p><code>ETag<\/code> is a version label whose contents the client need not interpret. The label is returned in <code>If-None-Match<\/code>. Its reliability depends on generation: a content hash or another suitable version scheme can distinguish changes that timestamps miss. An ETag is not automatically a content hash.<\/p>\n<p>A strong ETag identifies identical representation data. A weak ETag, such as <code>W\/\"abc\"<\/code>, permits equivalent data without byte identity. Dynamic generation does not automatically require weak tags: the actual comparison guarantee matters.<\/p>\n<h2>What the saved sample contains<\/h2>\n<p>The archived results contain five ETags, including three weak ones, and five Last-Modified fields. One response has both; eleven have neither. Six responses specify <code>no-store<\/code>, but only four of those lack both validators. Seven responses therefore lack validators without also specifying no-store. This alone does not establish cacheability: status, other directives and the cache context also matter.<\/p>\n<p>Two results carry an HTTP-error flag, including one of the two responses without Cache-Control. The saved summary does not preserve their exact status codes. The sample must therefore not be presented as twenty successful front-page responses or as a market statistic.<\/p>\n<p>The analyzer assigned six storage-prohibited, four immediate-refetch, three always-revalidate, four fresh-then-revalidate, one fresh-then-refetch and two heuristic labels. These are classifications of header observations, not measured browser histories. For example, the 54-second value was a max-age directive, not proof that every browser kept the response for exactly 54 seconds.<\/p>\n<h2>Freshness is separate from validation<\/h2>\n<p><code>no-store<\/code> prohibits HTTP-cache storage; <code>no-cache<\/code> requires successful validation before reuse. <code>max-age=0<\/code> makes a response immediately stale. Private and shared caches can have different rules, particularly with private or s-maxage.<\/p>\n<p>Without an explicit reuse period, a cache may estimate one under suitable conditions. This is called heuristic caching. Ten percent of the interval since Last-Modified is an example heuristic, not a mandatory lifetime. Neither of the two sampled responses without Cache-Control contained Last-Modified, so the archive does not demonstrate that calculation for those responses. Browser back\/forward mechanisms also cannot be inferred from this HTTP test.<\/p>\n<h2>Compression and the ETag trap<\/h2>\n<p>Apache documents that its default <code>AddSuffix<\/code> behavior in the compression modules can prevent 304 responses for compressed content. This makes a same-variant conditional test useful. A repeated 200 alone is insufficient evidence: the selected representation may genuinely have changed.<\/p>\n<p><code>DeflateAlterETag NoChange<\/code> and <code>BrotliAlterETag NoChange<\/code> preserve the original tag, but Apache explicitly documents the resulting variant-identity limitation. A shared strong tag for compressed and uncompressed bytes is not made correct by <code>Vary: Accept-Encoding<\/code>. Vary controls cache selection; strong validators concern representation identity.<\/p>\n<p>A suitable solution depends on the server and cache pipeline: correct distinct strong tags, properly handled weak tags for equivalent representations, or removal of an unsuitable ETag with the resulting validation trade-off. Range requests and conditional responses need verification. No universal production directive follows from a single 200 result. The earlier article&#8217;s claim that NoChange was unconditionally safe has therefore been removed.<\/p>\n\n\n<!-- lw-flux-illu 15683-a4 -->\n<figure class=\"lw-illu\"><img src=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/illustrationen\/flux-15683-a4.webp\" width=\"1120\" height=\"630\" loading=\"lazy\" decoding=\"async\" alt=\"Two duvets tied with the same ribbon, one fluffed up, one vacuum-packed flat. A shared ETag (a label for a file version) on compressed and uncompressed data is just as misleading.\"><figcaption>Two duvets tied with the same ribbon, one fluffed up, one vacuum-packed flat. A shared ETag (a label for a file version) on compressed and uncompressed data is just as misleading.<\/figcaption><\/figure>\n\n\n<h2>A reproducible conditional GET<\/h2>\n<p>The Bash example needs curl 7.68.0 or later. It keeps the URL and encoding preference unchanged, preserves the received ETag, and stops if the initial response is not 200 or supplies no tag. The URL is a placeholder; redirects require selecting and testing the intended final URL separately.<\/p>\n<figure style=\"--cbb-digits:2\" class=\"cbb cbb--wrap cbb--numbers wp-block-code-beautifier-block-code\" data-lang=\"bash\"><figcaption class=\"cbb-head\"><span class=\"cbb-lang\">Shell<\/span><span class=\"cbb-actions\"><button type=\"button\" class=\"cbb-button cbb-button--wrap\" data-cbb-action=\"wrap\" aria-pressed=\"true\" title=\"Wrap long lines\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><path d=\"M2 4h12M2 8h9.5a2.5 2.5 0 0 1 0 5H8m0 0 1.5-1.5M8 13l1.5 1.5M2 12h3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg><span class=\"cbb-sr\">Wrap long lines<\/span><\/button><button type=\"button\" class=\"cbb-button cbb-button--copy\" data-cbb-action=\"copy\" data-cbb-done=\"Copied\" data-cbb-failed=\"Press Ctrl+C to copy\"><svg aria-hidden=\"true\" focusable=\"false\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"><rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8.5\" rx=\"1.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><path d=\"M10.5 3.5V3A1.5 1.5 0 0 0 9 1.5H4A1.5 1.5 0 0 0 2.5 3v6.5A1.5 1.5 0 0 0 4 11h.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"\/><\/svg><span class=\"cbb-button-label\" aria-live=\"polite\">Copy<\/span><\/button><\/span><\/figcaption><pre class=\"cbb-pre\" tabindex=\"0\"><code class=\"cbb-code language-bash\" style=\"counter-reset:cbb-line 0;\"><span class=\"cbb-line\"><span class=\"cbb-comment\">#!\/usr\/bin\/env bash<\/span>\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">set<\/span> <span class=\"cbb-attr\">-euo<\/span> pipefail\n<\/span><span class=\"cbb-line\">url=<span class=\"cbb-string\">'https:\/\/example.com\/style.css'<\/span>\n<\/span><span class=\"cbb-line\">tag_file=<span class=\"cbb-variable\">$(<\/span>mktemp)\n<\/span><span class=\"cbb-line\"><span class=\"cbb-keyword\">trap<\/span> <span class=\"cbb-string\">'rm -f \"$tag_file\"'<\/span> EXIT\n<\/span><span class=\"cbb-line\">status=<span class=\"cbb-variable\">$(<\/span><span class=\"cbb-function\">curl<\/span> <span class=\"cbb-attr\">--silent<\/span> <span class=\"cbb-attr\">--show-error<\/span> <span class=\"cbb-attr\">--max-time<\/span> <span class=\"cbb-number\">20<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">-H<\/span> <span class=\"cbb-string\">'Accept-Encoding: gzip'<\/span> <span class=\"cbb-attr\">--etag-save<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$tag_file<\/span><span class=\"cbb-string\">\"<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--output<\/span> \/dev\/null <span class=\"cbb-attr\">--write-out<\/span> <span class=\"cbb-string\">'%{http_code}'<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$url<\/span><span class=\"cbb-string\">\"<\/span>)\n<\/span><span class=\"cbb-line\">&#91;&#91; <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$status<\/span><span class=\"cbb-string\">\"<\/span> == <span class=\"cbb-number\">200<\/span> &#93;&#93; <span class=\"cbb-operator\">||<\/span> { <span class=\"cbb-function\">printf<\/span> <span class=\"cbb-string\">'Initial HTTP status: %s\\n'<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$status<\/span><span class=\"cbb-string\">\"<\/span> <span class=\"cbb-operator\">&gt;<\/span>&amp;<span class=\"cbb-number\">2<\/span><span class=\"cbb-operator\">;<\/span> <span class=\"cbb-keyword\">exit<\/span> <span class=\"cbb-number\">1<\/span><span class=\"cbb-operator\">;<\/span> }\n<\/span><span class=\"cbb-line\">&#91;&#91; <span class=\"cbb-attr\">-s<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$tag_file<\/span><span class=\"cbb-string\">\"<\/span> &#93;&#93; <span class=\"cbb-operator\">||<\/span> { <span class=\"cbb-function\">printf<\/span> <span class=\"cbb-string\">'No ETag received\\n'<\/span> <span class=\"cbb-operator\">&gt;<\/span>&amp;<span class=\"cbb-number\">2<\/span><span class=\"cbb-operator\">;<\/span> <span class=\"cbb-keyword\">exit<\/span> <span class=\"cbb-number\">1<\/span><span class=\"cbb-operator\">;<\/span> }\n<\/span><span class=\"cbb-line\"><span class=\"cbb-function\">curl<\/span> <span class=\"cbb-attr\">--silent<\/span> <span class=\"cbb-attr\">--show-error<\/span> <span class=\"cbb-attr\">--max-time<\/span> <span class=\"cbb-number\">20<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">-H<\/span> <span class=\"cbb-string\">'Accept-Encoding: gzip'<\/span> <span class=\"cbb-attr\">--etag-compare<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$tag_file<\/span><span class=\"cbb-string\">\"<\/span> \\\n<\/span><span class=\"cbb-line\">  <span class=\"cbb-attr\">--output<\/span> \/dev\/null <span class=\"cbb-attr\">--dump-header<\/span> - <span class=\"cbb-attr\">--write-out<\/span> <span class=\"cbb-string\">'\\nHTTP %{http_code}\\n'<\/span> <span class=\"cbb-string\">\"<\/span><span class=\"cbb-variable\">$url<\/span><span class=\"cbb-string\">\"<\/span><\/span><\/code><\/pre><\/figure>\n<p>The displayed response headers make the second ETag and encoding visible. A 304 has no response body; a 200 needs examination of variant, modification and server behavior. Network failures and other status codes remain separate outcomes. Keeping Accept-Encoding identical controls one input, but does not prove that the server chose the same encoding or content.<\/p>\n<p>The <a href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/toolbox\/cache-control-revalidation-analyzer\/\">Cache-Control and Revalidation Analyzer<\/a> sends the received ETag and date in separate tests. It does not test their combined precedence or a full browser cache. Its byte counter measures decoded content, capped at 256 KiB, rather than complete compressed traffic. Its warnings also flag changed ETags returning 200; that can be valid behavior. The heuristic duration and classification require interpretation rather than automatic acceptance.<\/p>\n<div class=\"lw-faq\"><h2>Questions and answers<\/h2><h3>What happens when both conditions are sent?<\/h3><p>If-None-Match takes precedence; If-Modified-Since is ignored when that field is present. A matching date therefore does not override a nonmatching ETag. Actual client requests need inspection; every browser does not necessarily send both on every visit.<\/p><h3>Can a weak ETag produce 304?<\/h3><p>Yes. If-None-Match uses weak comparison, so <code>W\/\"abc\"<\/code> and <code>\"abc\"<\/code> match. That does not make a weak tag suitable for an entity-tag If-Range test or an If-Match strong comparison.<\/p><h3>Is every 200 evidence of a defect?<\/h3><p>No. A changed representation normally needs a new body. Diagnosis compares the request, selected variant and returned validator. Browser network tools, server logs and automated tests can expose the issue; manual curl is one method.<\/p><h3>Does 304 avoid a network round trip?<\/h3><p>No. A network validation still needs a response, possibly from an intermediary cache rather than the origin. A reusable fresh entry can avoid that request entirely. Versioned static assets can use longer freshness when the URL changes with every content update.<\/p><\/div>\n<div class=\"lw-quellen\"><h2>Sources<\/h2><ul><li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9110.html\" target=\"_blank\" rel=\"noopener noreferrer\">RFC 9110: HTTP Semantics<\/a><\/li><li><a href=\"https:\/\/www.rfc-editor.org\/rfc\/rfc9111.html\" target=\"_blank\" rel=\"noopener noreferrer\">RFC 9111: HTTP Caching<\/a><\/li><li><a href=\"https:\/\/httpd.apache.org\/docs\/2.4\/mod\/mod_deflate.html#deflatealteretag\" target=\"_blank\" rel=\"noopener noreferrer\">Apache: DeflateAlterETag<\/a><\/li><li><a href=\"https:\/\/httpd.apache.org\/docs\/2.4\/mod\/mod_brotli.html#brotlialteretag\" target=\"_blank\" rel=\"noopener noreferrer\">Apache: BrotliAlterETag<\/a><\/li><li><a href=\"https:\/\/curl.se\/docs\/manpage.html\" target=\"_blank\" rel=\"noopener noreferrer\">curl manual<\/a><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Conditional requests can save response bodies, while fresh cache entries can avoid requests entirely. A historical sample of twenty responses shows missing validators, interpretation limits and an ETag pitfall with compression.<\/p>\n","protected":false},"author":1,"featured_media":24517,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[158],"tags":[91099,91219,91315],"class_list":["post-15683","post","type-post","status-publish","format-standard","hentry","category-tutorials-en-web-development","tag-server-administration","tag-tutorial","tag-web-performance"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik<\/title>\n<meta name=\"description\" content=\"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik\" \/>\n<meta property=\"og:description\" content=\"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-11-09T07:05:00+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Lukas Wojcik\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lukas Wojcik\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/\"},\"author\":{\"name\":\"Lukas Wojcik\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"headline\":\"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304\",\"datePublished\":\"2026-11-09T07:05:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/\"},\"wordCount\":984,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/quality-hero-15683-20261025.png\",\"keywords\":[\"Server Administration\",\"Tutorial\",\"Web Performance\"],\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/\",\"name\":\"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/quality-hero-15683-20261025.png\",\"datePublished\":\"2026-11-09T07:05:00+00:00\",\"description\":\"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/quality-hero-15683-20261025.png\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/10\\\/quality-hero-15683-20261025.png\",\"width\":1200,\"height\":630,\"caption\":\"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/en\\\/web-development\\\/tutorials-en-web-development\\\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"Lukas Wojcik\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"Lukas Wojcik\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik","description":"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/","og_locale":"en_US","og_type":"article","og_title":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik","og_description":"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/","og_site_name":"Lukas Wojcik - Blog","article_published_time":"2026-11-09T07:05:00+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png","type":"image\/png"}],"author":"Lukas Wojcik","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Lukas Wojcik","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#article","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/"},"author":{"name":"Lukas Wojcik","@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"headline":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304","datePublished":"2026-11-09T07:05:00+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/"},"wordCount":984,"commentCount":0,"publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png","keywords":["Server Administration","Tutorial","Web Performance"],"articleSection":["Tutorials"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/","url":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/","name":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304 | Lukas Wojcik","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#primaryimage"},"image":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png","datePublished":"2026-11-09T07:05:00+00:00","description":"How a conditional request works, why eleven of twenty front pages carry no validator, and a stylesheet that never answered 304.","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#primaryimage","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/10\/quality-hero-15683-20261025.png","width":1200,"height":630,"caption":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/en\/web-development\/tutorials-en-web-development\/the-question-that-saves-nothing-etag-last-modified-and-the-missing-304\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"The Question That Saves Nothing: ETag, Last-Modified and the Missing 304"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"Lukas Wojcik","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"Lukas Wojcik"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15683","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=15683"}],"version-history":[{"count":8,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15683\/revisions"}],"predecessor-version":[{"id":30360,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/posts\/15683\/revisions\/30360"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media\/24517"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=15683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/categories?post=15683"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=15683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}