{"id":430,"date":"2010-12-10T12:35:32","date_gmt":"2010-12-10T11:35:32","guid":{"rendered":"https:\/\/d-mueller.de\/blog\/?p=430"},"modified":"2011-08-29T10:19:36","modified_gmt":"2011-08-29T08:19:36","slug":"der-einfluss-von-cookies-auf-die-performance-einer-webseite","status":"publish","type":"post","link":"https:\/\/d-mueller.de\/blog\/der-einfluss-von-cookies-auf-die-performance-einer-webseite\/","title":{"rendered":"Der Einfluss von Cookies auf die Performance einer Webseite"},"content":{"rendered":"<p>Cookies werden oft missachtet, wenn es um die Optimierung einer Webseite hinsichtlich Performance geht &#8211; zu unrecht! Das wunderbare <a href=\"https:\/\/addons.mozilla.org\/de\/firefox\/addon\/5369\/\">YSlow<\/a> von Yahoo zum Beispiel hat einen Test eingebaut, der genau darauf abzielt. In den <a href=\"http:\/\/developer.yahoo.com\/performance\/rules.html\">Performance Grunds\u00e4tzen<\/a> dazu hei\u00dft die Leitregel <i>Use Cookie-free Domains for Components<\/i>.<\/p>\n<h2>Das Problem<\/h2>\n<p>Cookies k\u00f6nnen erstmal in beliebiger Anzahl und ziemlicher Gr\u00f6\u00dfe auf Clientseite abgelegt werden. Das Setzen von Cookies geht sowohl mittels Javascript wie auch von der Serverseite aus, bspw. mit PHP. Womit der Cookie gesetzt wird, ist letztendlich egal. Der Effekt auf das Ladeverhalten der Webseite ist in jedem Fall, dass <b>bei jedem HTTP-Request vom Client aus alle Cookies im Anfrage-Header mit \u00fcbermittelt<\/b> werden. Hei\u00dft konkret: <i>MeineWebseite.com<\/i> verpasst euch beim ersten Besuch 5 Cookies, jeder 600 Byte gro\u00df. Jetzt besteht die Seite aus 30 Images, 5 Javascripts und 8 CSS-Files &#8211; garkein un\u00fcbliches Setup. Das Dokument selbst noch hinzugerechnet haben wir also 1+30+5+8 = 44 HTTP-Requests. (<b>Update:<\/b> <a href=\"http:\/\/phpperformance.de\/server-side-cookies\/\">Danke f\u00fcr das Aufdecken des Rechenfehlers<\/a>)<\/p>\n<p>Damit w\u00fcrde diese imagin\u00e4re Seite sogar noch im &#8222;Normalbereich&#8220; liegen, verglichen etwa mit <a href=\"http:\/\/mashable.com\/\">mashable.com<\/a> mit 451 HTTP Requests (<b>!!!<\/b>). So, zur\u00fcck auf unser Beispiel. Bei jedem HTTP-Request werden alle Cookies (5 St\u00fcck \u00e0 600 Byte ~ 3KB) vom Client an den Server \u00fcbertragen, also bei 44 HTTP-Requests macht das 44*3KB = 132KB zus\u00e4tzlichen Upload. Das ist schon &#8217;ne Hausnummer. Wenn ich jetzt mal an Leute auf dem Land mit DSL Lite 768 und 128Kbit (16KB\/sec) Upload denke, m\u00fcssten die allein schonmal mehr als 8 Sekunden cookiebedingte Wartezeit in Kauf nehmen &#8211; unn\u00fctz! Denn wozu brauchen statische Elemente wie Bilder oder CSS-Dateien Zugriff auf die Cookies?<\/p>\n<h2>Beispiel-Setup<\/h2>\n<pre data-enlighter-language=\"html\" class=\"EnlighterJSRAW\">\r\n&lt;?php\r\n\tsetcookie(&quot;PHP-Cookie&quot;, &quot;I was set by PHP&quot;, time()+3*86400);\r\n?&gt;\r\n\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n\t&lt;link rel=&quot;stylesheet&quot; href=&quot;css\/style.css&quot; \/&gt;\r\n\t\t\r\n\t&lt;script&gt;\r\n\tfunction setCookie(cookiename,value,expiredays)\r\n\t{\r\n\t\tvar expires=new Date();\r\n\t\texpires.setDate(expires.getDate()+expiredays);\r\n\t\texpires = expires.toUTCString();\r\n\t\t\r\n\t\tdocument.cookie=cookiename+&quot;=&quot;+escape(value)+&quot;;expires=&quot;+expires;\r\n\t}\r\n\t\r\n\tsetCookie(&quot;Javascript-Cookie&quot;,&quot;I was set by Javascript&quot;,3);\r\n\t&lt;\/script&gt;\r\n\t\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n\t&lt;img src=&quot;images\/image.png&quot; \/&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Wir setzen also einen PHP-Cookie und einen Javascript-Cookie (jeweils f\u00fcr 3 Tage, aber das hat f\u00fcr dieses Beispiel keine Bedeutung). <\/p>\n<p>Damit haben wir folgendes Szenario:<\/p>\n<pre>\r\nRequest: http:\/\/cookietest.de\/index.php\r\nImages:  http:\/\/cookietest.de\/images\/image.png\r\nStyles:  http:\/\/cookietest.de\/css\/style.css\r\n<\/pre>\n<p><b>Im Firebug betrachtet sieht das so aus:<\/b><\/p>\n<p><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/cookies.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/cookies-300x190.png\" alt=\"\" title=\"cookies\" width=\"300\" height=\"190\" class=\"alignnone size-medium wp-image-431\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/cookies-300x190.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/cookies.png 748w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Der PHP und der Javascript-Cookie wird mit dem Bild (wie mit den anderen beiden Requests auch) mitgeschickt, obwohl weder das Bild, noch die CSS was damit angefangen kann.<\/p>\n<p><b>Der Cookie-Editor verr\u00e4t:<\/b><\/p>\n<p><a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-js-cookie.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-js-cookie-300x170.png\" alt=\"\" title=\"1-js-cookie\" width=\"300\" height=\"170\" class=\"alignnone size-medium wp-image-432\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-js-cookie-300x170.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-js-cookie.png 485w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-php-cookie.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-php-cookie-300x167.png\" alt=\"\" title=\"1-php-cookie\" width=\"300\" height=\"167\" class=\"alignnone size-medium wp-image-433\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-php-cookie-300x167.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/1-php-cookie.png 483w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Damit sind beide Cookies f\u00fcr die ganze Domain g\u00fcltig, somit also auch f\u00fcr das Bild und die CSS-Datei.<\/p>\n<h2>L\u00f6sungsm\u00f6glichkeiten<\/h2>\n<h3>1) Den Content in ein Subdirectory packen und die Cookies auf dieses limitieren<\/h3>\n<pre>\r\nRequest: http:\/\/cookietest.de\/content\/index.php\r\nImages:  http:\/\/cookietest.de\/images\/image.png\r\nStyles:  http:\/\/cookietest.de\/css\/style.css\r\n<\/pre>\n<p>Nur die Content-Dateien (PHP-Files) haben in der Regel mit den Cookies zu tun. Wenn wir also die G\u00fcltigkeit der Cookies auf dieses Verzeichnis beschr\u00e4nken, bleiben die statischen Ressourcen davon unbehelligt. Damit ver\u00e4ndert sich der PHP-setcookie-Befehl wie folgt:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nsetcookie(&quot;PHP-Cookie&quot;, &quot;I was set by PHP&quot;, time()+3*86400, &quot;\/content\/&quot;);\r\n<\/pre>\n<p>F\u00fcr Javascript gilt:<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\nfunction setCookie(cookiename,value,expiredays,path)\r\n{\r\n\tvar expires=new Date();\r\n\texpires.setDate(expires.getDate()+expiredays);\r\n\texpires = expires.toUTCString();\r\n\t\r\n\tdocument.cookie=cookiename+&quot;=&quot;+escape(value)+&quot;;expires=&quot;+expires+&quot;;path=&quot;+path;\r\n}\r\n\r\nsetCookie(&quot;Javascript-Cookie&quot;,&quot;I was set by Javascript&quot;,3,&quot;\/content\/&quot;);\r\n<\/pre>\n<p>Damit werden nur noch f\u00fcr die Dateien im \/content\/* &#8211; Unterverzeichnis Cookies \u00fcbertragen und nicht mehr f\u00fcr Bilder und CSS-Dateien. <b>Nur ist es oft (unter anderem aus SEO-Gr\u00fcnden) nicht sinnvoll, den ganzen Inhalt in einen Unterordner zu verfrachten.<\/b><\/p>\n<h3>2) Eine Subdomain f\u00fcr alle statischen Inhalte anlegen<\/h3>\n<pre>\r\nRequest: http:\/\/cookietest.de\/index.php\r\nImages:  http:\/\/static.cookietest.de\/images\/image.png\r\nStyles:  http:\/\/static.cookietest.de\/css\/style.css\r\n<\/pre>\n<p>Wenn wir jetzt den Code also so umbauen, dass alle statischen Ressourcen von dieser Subdomain geladen werden, k\u00f6nnten wir es wie folgt aufbauen:<\/p>\n<pre data-enlighter-language=\"html\" class=\"EnlighterJSRAW\">\r\n&lt;?php\r\nsetcookie(&quot;PHP-Cookie&quot;, &quot;I was set by PHP&quot;, time()+3*86400, &quot;\/&quot;, &quot;cookietest.de&quot;);\r\n?&gt;\r\n\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n&lt;head&gt;\r\n\t&lt;link rel=&quot;stylesheet&quot; href=&quot;http:\/\/static.cookietest.de\/css\/style.css&quot; \/&gt;\r\n\t\t\r\n\t&lt;script&gt;\r\n\tfunction setCookie(cookiename,value,expiredays,path, domain)\r\n\t{\r\n\t\tvar expires=new Date();\r\n\t\texpires.setDate(expires.getDate()+expiredays);\r\n\t\texpires = expires.toUTCString();\r\n\t\t\r\n\t\tdocument.cookie=cookiename+&quot;=&quot;+escape(value)+&quot;;expires=&quot;+expires+&quot;;path=&quot;+path+&quot;;domain=&quot;+domain;\r\n\t}\r\n\r\n\tsetCookie(&quot;Javascript-Cookie&quot;,&quot;I was set by Javascript&quot;,3,&quot;\/&quot;, &quot;cookietest.de&quot;);\r\n\t&lt;\/script&gt;\r\n\t\r\n&lt;\/head&gt;\r\n&lt;body&gt;\r\n\t&lt;img src=&quot;http:\/\/static.cookietest.de\/images\/image.png&quot; \/&gt;\r\n&lt;\/body&gt;\r\n&lt;\/html&gt;\r\n<\/pre>\n<p>Wenn wir uns jetzt aber den Firebug betrachten, sehen wir allerdings auch wieder bei den statischen Elementen<\/p>\n<pre data-enlighter-language=\"enlighter\" class=\"EnlighterJSRAW\">\r\nCookie\tPHP-Cookie=I+was+set+by+PHP; Javascript-Cookie=I%20was%20set%20by%20Javascript\r\n<\/pre>\n<p>Wie kommt das?<br \/>\n<a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-js-cookie.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-js-cookie-300x169.png\" alt=\"\" title=\"2-js-cookie\" width=\"300\" height=\"169\" class=\"alignnone size-medium wp-image-435\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-js-cookie-300x169.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-js-cookie.png 486w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\n<a href=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-php-cookie.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-php-cookie-300x168.png\" alt=\"\" title=\"2-php-cookie\" width=\"300\" height=\"168\" class=\"alignnone size-medium wp-image-436\" srcset=\"https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-php-cookie-300x168.png 300w, https:\/\/d-mueller.de\/blog\/wp-content\/uploads\/2010\/12\/2-php-cookie.png 482w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Der aufmerksame Beobachter sieht sofort: Als Domain ist <\/p>\n<pre data-enlighter-language=\"enlighter\" class=\"EnlighterJSRAW\">.cookietest.de<\/pre>\n<p> eingetragen, was bedeutet, dass die Subdomains ebenfalls davon betroffen sind &#8211; <b>Also hilft uns diese L\u00f6sung in der Form noch nicht weiter<\/b>, weil die statischen Dateien trotz Subdomain die Cookies angehangen bekommen.<\/p>\n<h3>Die L\u00f6sung hei\u00dft www.<\/h3>\n<p>Wenn wir also nur noch <i>www.<\/i>-Aufrufe f\u00fcr die Webseite zulassen, k\u00f6nnen wir die Cookies auch auf <i>www.cookietest.de<\/i> beschr\u00e4nken. Damit bleibt die Subdomain unbehelligt.<\/p>\n<p><b>Damit:<\/b><\/p>\n<pre>\r\nRequest: http:\/\/www.cookietest.de\/index.php\r\nImages:  http:\/\/static.cookietest.de\/images\/image.png\r\nStyles:  http:\/\/static.cookietest.de\/css\/style.css\r\n<\/pre>\n<p>PHP:<\/p>\n<pre data-enlighter-language=\"php\" class=\"EnlighterJSRAW\">\r\nsetcookie(&quot;PHP-Cookie&quot;, &quot;I was set by PHP&quot;, time()+3*86400, &quot;\/&quot;, &quot;www.cookietest.de&quot;);\r\n<\/pre>\n<p>Javascript:<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\nsetCookie(&quot;Javascript-Cookie&quot;,&quot;I was set by Javascript&quot;,3,&quot;\/&quot;, &quot;www.cookietest.de&quot;);\r\n<\/pre>\n<p>Wenn wir nun noch in der .htacess mittels<\/p>\n<pre data-enlighter-language=\"enlighter\" class=\"EnlighterJSRAW\">\r\n#force www.\r\nRewriteCond %{HTTP_HOST} ^cookietest.de$ [NC]\r\nRewriteRule ^(.*) http:\/\/www.cookietest.de\/$1 [L,R=301]\r\n<\/pre>\n<p>erzwingen, dass die Seite blo\u00df mit www. aufgerufen kann, <b>haben wir gewonnen<\/b>.<\/p>\n<h3>3) Komplett andere Domain f\u00fcr statische Inhalte verwenden<\/h3>\n<p>Wir k\u00f6nnen es uns noch einfacher machen, wenn wir eine komplett andere Domain f\u00fcr statische Inhalte verwenden, etwa <i>cookietest-static.de<\/i>. Damit brauchen wir uns um nichts mehr zu k\u00fcmmern, brauchen keine Cookies einschr\u00e4nken oder mit Subdomains herumexperimentieren. Ist halt eine Kostenfrage.<\/p>\n<h2>Aber Vorsicht!<\/h2>\n<p>Im hier gezeigen Beispiel mit 3 HTTP-Requests w\u00e4re der getriebene Aufwand Overkill, da es kaum merkliche Unterschiede in der Seitengeschwindigkeit geben w\u00fcrde. Auch zu beachten ist, dass durch das Auslagern statischer Inhalte auf eine andere Domain ein zus\u00e4tzlicher <i>DNS-Lookup<\/i> n\u00f6tig wird, um <i>cookietest-static.de<\/i> zu einer IP aufzul\u00f6sen. Ma\u00dfgabe ist also, genau abzuw\u00e4gen wann es sich lohnt, den obigen Aufwand zu treiben.<\/p>\n<h2>Zukunftsaussicht<\/h2>\n<p>Es wird gerade eifrig diskutiert, ob in Browsern der Zusatz <i>rel=&#8220;anonymous&#8220;<\/i> bei statischen Elementen eingef\u00fchrt werden sollte. Diese sollen dann keine Cookie-Daten mitgeschickt bekommen. W\u00e4re an sich eine super Sache, nur sind dann trotzdem noch genug Leute mit alten Browsern unterwegs und f\u00fcr per CSS geladene Bilder w\u00fcrde das wohl auch nicht greifen &#8211; Mal sehen, wohin die Reise geht.<\/p>\n<h2>Bonus: Google Analytics auf eine Domain beschr\u00e4nken<\/h2>\n<p>Google Analytics setzt selbst auch einen Cookie mit einer ID, die dann zum Tracking des Benutzers verwendet wird. Mit den Anweisungen <i>_setDomainName<\/i> und <i>_setCookiePath<\/i> l\u00e4sst sich dieser aber auch auf die relevanten Content-Seiten beschr\u00e4nken, um eben zu verhindern, dass auch bei statischen Ressourcen immer der Cookie mit \u00fcbertragen wird. Bei mir sieht das jetzt so aus:<\/p>\n<pre data-enlighter-language=\"js\" class=\"EnlighterJSRAW\">\r\nvar _gaq = _gaq || [];\r\n_gaq.push([&#039;_setAccount&#039;,&#039;UA-2935194-4&#039;]);\r\n_gaq.push([&#039;_setDomainName&#039;, &#039;www.d-mueller.de&#039;]); \r\n_gaq.push([&#039;_setCookiePath&#039;, &#039;\/blog\/&#039;]);\r\n_gaq.push([&#039;_trackPageview&#039;]);\r\n(function() {\r\n\tvar ga = document.createElement(&#039;script&#039;); ga.type = &#039;text\/javascript&#039;; ga.async = true;\r\n\tga.src = (&#039;https:&#039; == document.location.protocol ? &#039;https:\/\/ssl&#039; : &#039;http:\/\/www&#039;) + &#039;.google-analytics.com\/ga.js&#039;;\r\n\tvar s = document.getElementsByTagName(&#039;script&#039;)[0]; s.parentNode.insertBefore(ga, s);\r\n})();\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Cookies werden oft missachtet, wenn es um die Optimierung einer Webseite hinsichtlich Performance geht &#8211; zu unrecht! Das wunderbare YSlow von Yahoo zum Beispiel hat einen Test eingebaut, der genau darauf abzielt. In den Performance Grunds\u00e4tzen dazu hei\u00dft die Leitregel &hellip; <a href=\"https:\/\/d-mueller.de\/blog\/der-einfluss-von-cookies-auf-die-performance-einer-webseite\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,12,10,3],"tags":[],"class_list":["post-430","post","type-post","status-publish","format-standard","hentry","category-php","category-javascript","category-performance","category-webdev"],"_links":{"self":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/430","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/comments?post=430"}],"version-history":[{"count":0,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/posts\/430\/revisions"}],"wp:attachment":[{"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/media?parent=430"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/categories?post=430"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/d-mueller.de\/blog\/wp-json\/wp\/v2\/tags?post=430"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}