8. The Client sends a Request to the Server
The Server sends back a Response to the Client
A Client (browser, bot,WS, curl, …)
A Server (Apache, nginx, …)
The Request and the Response are HTTP messages
11. « The request-header fields allow the client to pass additional
information about the request, and about the client itself, to the
server.These fields act as request modifiers, with semantics
equivalent to the parameters on a programming language method
invocation. »
12. « Each HTTP header field consists of a case-insensitive field name
followed by a colon (":"), optional whitespace, and the field value »
13. HTTP/1.1 200 OK
Date: Wed, 15 Oct 2005 07:07:07 GMT
Server: Apache
Content-Length: 14
Content-Type: text/html
Hello World!
14. Live HTTP headers Firefox extension
http://livehttpheaders.mozdev.org/
28. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
GET /foo
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
30. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
GET /foo
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
HTTP/1.1 200 OK
Expires: Thu,
01
Dec
…
Hello
A<er
expira4on
Not
fresh
31. Expires: Thu, 01 Dec 2010 16:00:00 GMT
Date in RFC1123 format, not RFC2822
(timezone always GMT, which is ~ UTC)
33. $date = new DateTime(null, new DateTimeZone('UTC'));
$date->modify('+5 seconds');
$expires = $date->format('D, d M Y H:i:s').' GMT';
$date = gmdate('D, j M Y H:i:s T', time() + 5);
header('Expires: '.$expires);
47. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: abcdef
HTTP/1.1 304 Not Modified
GET /foo
HTTP/1.1 200 OK
ETag: abcdef
…
Hello
HTTP/1.1 200 OK
ETag: abcdef
Hello
If
the
resource
has
not
changed
48. SomeCache
GET /foo
HTTP/1.1 200 OK
ETag: abcdef
…
Hello
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: abcdef
If
the
resource
has
changed
GET /foo
HTTP/1.1 200 OK
ETag: 123456
…
Hello
HTTP/1.1 200 OK
ETag: 123456
Hello
HTTP/1.1 200 OK
ETag: 123456
Hello
49. // compute ETag value
$etag = '...';
if (
isset($_SERVER['HTTP_IF_NONE_MATCH'])
&& $_SERVER['HTTP_IF_NONE_MATCH'] == $etag
) {
header('HTTP/1.1 304 Not Modified');
} else {
header('ETag: '.$etag);
echo 'Hello';
}
52. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
53. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-Modified-Since: Thu,
HTTP/1.1 304 Not Modified
GET /foo
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
If
the
resource
has
not
changed
54. SomeCache
GET /foo
HTTP/1.1 200 OK
Last-Modified: Thu,
…
Hello
GET /foo
HTTP/1.1 200 OK
Last-Modified: Sun,
…
Hello
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-Modified-Since: Thu,
If
the
resource
has
changed
HTTP/1.1 200 OK
Last-Modified: Sun,
…
Hello
HTTP/1.1 200 OK
Last-Modified: Sun,
…
Hello
56. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo
HTTP/1.1 200 OK
Etag: abcdef
Cache-‐Control:
max-‐
age=10
…
Hello
HTTP/1.1 200 OK
ETag: abcdef
Cache-‐Control:
max-‐age=10
Hello
HTTP/1.1 200 OK
ETag: abcdef
Cache-‐Control:
max-‐age=10
Hello
57. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
Before
expira4on
Your
applica4on
is
not
called
GET /foo
HTTP/1.1 200 OK
Etag: abcdef
Cache-‐Control:
max-‐
age=10
…
Hello
HTTP/1.1 200 OK
ETag: abcdef
Cache-‐Control:
max-‐age=10
Hello
58. Browser
YourPHPapplication
SomeCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: abcdef
HTTP/1.1 304 Not Modified
Cache-‐Control:
max-‐age=10
A<er
expira4on
but
resource
s4ll
valid
GET /foo
HTTP/1.1 200 OK
Etag: abcdef
Cache-‐Control:
max-‐
age=10
…
Hello
HTTP/1.1 200 OK
ETag: abcdef
Cache-‐Control:
max-‐age=10
Hello
59. You can combine HTTP headers
the way you want
Expiration wins overValidation
60. Expiration allows you to scale
as less requests hit your server
(and client speed is better too)
Validation saves bandwidth
61. The goal is to never
generate the same response twice
71. On
the
server
side
Within
a
Company
Browser
YourPHPapplication
BrowserBrowser
BrowserCacheBrowserCacheBrowserCache
ProxyCache
72. On
the
server
side
Within
a
Company
Browser
YourPHPapplication
BrowserBrowser
BrowserCacheBrowserCacheBrowserCache
ProxyCache
Within
a
Company
BrowserBrowserBrowser
BrowserCacheBrowserCacheBrowserCache
ProxyCache
74. On
the
server
side
YourPHPapplication
Browser
BrowserCache
GatewayCache
75. Within
a
Company
On
the
server
side
Browser
YourPHPapplication
BrowserBrowser
BrowserCacheBrowserCacheBrowserCache
GatewayCache
76. On
the
server
side
Within
a
Company
Browser
YourPHPapplication
BrowserBrowser
BrowserCacheBrowserCacheBrowserCache
ProxyCache
BrowserBrowser
BrowserCacheBrowserCache
GatewayCache
79. Proxy Cache
A shared cache
Many people behind a single proxy
Installed by large corporations and ISPs
Reduce latency and network traffic
80. Gateway Cache
A shared cache on the server side
Installed by network administrators
Make websites more scalable, reliable and performing better
CDNs like Akaïma are gateway caches
85. In practice, most caches avoid anything with
Cache-Control
Cookie / Set-Cookie
WWW-Authenticate / Authorization
POST / PUT
302 / 307 status codes
86. Cache-Control: private
This is the default with PHP when you have a session
Browser cache will still work fine here
(public means shared caches, private means browser cache)
87. A gateway cache won't cache anything
"private" or carrying a cookie
In a real-world: tracking cookies (Google Analytics)
93. BrowserCache
Alice
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
HTTP/1.1 200 OK
C-C: max-age=600
Hello
HTTP/1.1 200 OK
C-C: max-age=600
Hello
GatewayCache
GET /foo
HTTP/1.1 200 OK
C-C: max-age=600
…
Hello
GET /foo
HTTP/1.1 200 OK
C-C: max-age=600
…
Hello
95. Bob’sCache
GatewayCache
Bob
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo
HTTP/1.1 200 OK
Etag: abcde
…
Hello
HTTP/1.1 200 OK
Etag: abcde
Hello
HTTP/1.1 200 OK
Etag: abcde
Hello
GET /foo
HTTP/1.1 200 OK
Etag: abcde
…
Hello
HTTP/1.1 200 OK
Etag: abcde
Hello
96. Bob’sCache
GatewayCache
Bob
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: ab
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: ab
GET /foo
HTTP/1.1 200 OK
Etag: ab
…
Hello
HTTP/1.1 200 OK
Etag: ab
Hello
GET /foo
HTTP/1.1 200 OK
Etag: ab
…
Hello
304 Not Modified304 Not Modified
97. GatewayCache
YourPHPapplication
BrowserCache
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
If-None-Match: ab
GET /foo
HTTP/1.1 200 OK
Etag: ab
…
Hello
HTTP/1.1 200 OK
Etag: ab
Hello
304 Not Modified
Alice
HTTP/1.1 200 OK
Etag: ab
Hello
GET /foo
HTTP/1.1 200 OK
Etag: ab
…
Hello
98. Gateway caches
Varnish (only does that and tries to do it well)
Squid (just one way to use it)
mod_cache (Apache)
100. But what if you cannot cache whole pages?
What if a page has "more" dynamic parts?
101. Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus,
in
pulvinar
lectus
rutrum
sit
amet.
Duis
gravida,
metus
in
dictum
eleifend,
dolor
risus
4ncidunt
ligula,
non
volutpat
nulla
sapien
in
elit.
Nulla
rutrum
erat
id
neque
suscipit
eu
ultricies
odio
sollicitudin.
Aliquam
a
mi
vel
eros
placerat
hendrerit.
Phasellus
porRtor,
augue
sit
amet
vulputate
venena4s,
dui
leo
commodo
odio,
a
euismod
turpis
ligula
in
elit.
cacheable for 10 seconds
cacheable for 5 seconds
102. ESI… or Edge Side Includes
http://www.w3.org/TR/esi-lang
103. Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus,
in
pulvinar
lectus
rutrum
sit
amet.
Duis
gravida,
metus
in
dictum
eleifend,
dolor
risus
4ncidunt
ligula,
non
volutpat
nulla
sapien
in
elit.
Nulla
rutrum
erat
id
neque
suscipit
eu
ultricies
odio
sollicitudin.
Aliquam
a
mi
vel
eros
placerat
hendrerit.
Phasellus
porRtor,
augue
sit
amet
vulputate
venena4s,
dui
leo
commodo
odio,
a
euismod
turpis
ligula
in
elit.
104. Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus,
in
pulvinar
lectus
rutrum
sit
amet.
Duis
gravida,
metus
in
dictum
eleifend,
dolor
risus
4ncidunt
ligula,
non
volutpat
nulla
sapien
in
elit.
Nulla
rutrum
erat
id
neque
suscipit
eu
ultricies
odio
sollicitudin.
Aliquam
a
mi
vel
eros
placerat
hendrerit.
Phasellus
porRtor,
augue
sit
amet
vulputate
venena4s,
dui
leo
commodo
odio,
a
euismod
turpis
ligula
in
elit.
<esi:include src="..." />
106. BrowserCache
GatewayCache
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /bar HTTP/1.1
Host: foo.org
Lorem
ipsum
dolor
<esi:include
src="hYp.."
/>
HTTP/1.1 200 OK
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
107. BrowserCache
GatewayCache
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /bar HTTP/1.1
Host: foo.org
Lorem
ipsum
dolor
<esi:include
src="hYp.."
/>
HTTP/1.1 200 OK
C-C: max-age=10
Lorem
ipsum
dolor
HTTP/1.1 200 OK
C-C: max-age=5
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
GET /foo
C-C: max-age=10
Lor <esi:include />
GET /bar
C-C: max-age=5
Lorem
GET /foo
C-C: max-age=10
Lor Lorem
111. BrowserCache
GatewayCache
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /bar HTTP/1.1
Host: foo.org
Lorem
ipsum
dolor
<esi:include
src="hYp.."
/>
HTTP/1.1 200 OK
C-C: s-maxage=10
Lorem
ipsum
dolor
HTTP/1.1 200 OK
C-C: s-maxage=5
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
GET /foo
C-C: s-maxage=10
Lor <esi:include />
GET /bar
C-C: s-maxage=5
Lorem
112. BrowserCache
GatewayCache
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
GET /foo
C-C: s-maxage=10
Lor <esi:include />
GET /bar
C-C: s-maxage=5
Lorem
2
seconds
later…
113. BrowserCache
GatewayCache
Browser
YourPHPapplication
GET /foo HTTP/1.1
Host: foo.org
GET /foo HTTP/1.1
Host: foo.org
GET /bar HTTP/1.1
Host: foo.org
Lorem
ipsum
dolor
HTTP/1.1 200 OK
C-C: s-maxage=5
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
Lorem
ipsum
dolor
sit
amet,
Lorem
ipsum
dolor
HTTP/1.1 200 OK
GET /foo
C-C: s-maxage=10
Lor <esi:include />
GET /bar
C-C: s-maxage=5
Lorem
7
seconds
later…
114. Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Mauris
dignissim,
urna
quis
iaculis
tempus,
justo
libero
porRtor
est,
nec
eleifend
est
elit
vitae
ante.
Curabitur
interdum
luctus
metus,
in
pulvinar
lectus
rutrum
sit
amet.
Duis
gravida,
metus
in
dictum
eleifend,
dolor
risus
4ncidunt
ligula,
non
volutpat
nulla
sapien
in
elit.
Nulla
rutrum
erat
id
neque
suscipit
eu
ultricies
odio
sollicitudin.
Aliquam
a
mi
vel
eros
placerat
hendrerit.
Phasellus
porRtor,
augue
sit
amet
vulputate
venena4s,
dui
leo
commodo
odio,
a
euismod
turpis
ligula
in
elit.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
Integer
semper
turpis
et
enim
porRtor
iaculis.
Nulla
facilisi.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
Mauris
vehicula
ves4bulum
dictum.
Aenean
non
velit
tortor.
Nullam
adipiscing
malesuada
aliquam.
Lorem
ipsum
dolor
sit
amet,
consectetur
adipiscing
elit.
In
vel
nulla
arcu,
vitae
cursus
nunc.
main template
layout
base layout
included page
included page
included page
126. Imagine the power when you combine
ESI, expiration, validation, max-age, s-maxage, …
127. Why would you want to reinvent the wheel?
and implement your own caching system?
128. Because you cannot afford to useVarnish?
Because you use a shared hosting company?
129. <?php
// With the Symfony2 HTTP accelerator instead of Varnish
// won't work if you use exit() for instance...
// won't work if you have "global" state
// This is just a skeleton to get you started
// Of course, this is native with Symfony2 ;)
130. use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpKernelHttpKernelInterface;
use SymfonyComponentHttpKernelCacheCache;
use SymfonyComponentHttpKernelCacheEsi;
use SymfonyComponentHttpKernelCacheStore;
class AppKernel implements HttpKernelInterface
{
public function handle(Request $request = null, $type
= HttpKernelInterface::MASTER_REQUEST, $raw = false)
{
return new Response($content, 200, $headers);
}
public function getRequest() {}
}
131. $_SERVER['HTTP_SURROGATE_CAPABILITY'] = 'symfony2="ESI/1.0"';
// quick hack... not secure at all!
$base = str_replace('index.php', '', $request->getScriptName());
$script = str_replace($base, '', $request->getRequestUri());
ob_start();
include __DIR__.'/'.$script;
$content = ob_get_clean();
$headers = array();
foreach (headers_list() as $header) {
$elements = explode(':', $header, 2);
$headers[$elements[0]] = trim($elements[1]);
}
// do not deal with response others than 200
// implementation depends on your code
return new Response($content, 200, $headers);
132. $kernel = new AppKernel();
$store = new Store('/path/to/http_cache');
$esi = new Esi();
$cache = new Cache($kernel, $store, $esi);
$cache->handle()->send();
error_log($cache->getLog());