You need to retrieve the same content more than once, and you would like to have the server only send the content if it has changed since the last request.
Create a GetMethod
and set the
If-None-Match
and If-Modified-Since
headers; these two headers
will instruct the server to refrain from sending content if the content
has not been altered since the last request. Example 11-1 makes three separate
requests for the same URL (http://www.apache.org), and, because
the content remains static, it is only sent in the response body of the
first request.
Example 11-1. Requesting information with a conditional GET
import java.io.IOException; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HeaderElement; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.GetMethod; public class ConditionalGetExample { public static void main(String[] args) throws HttpException, IOException { ConditionalGetExample example = new ConditionalGetExample( ); example.start( ); } String entityTag = ""; String lastModified = ""; public void start( ) throws HttpException, IOException { HttpClient client = new HttpClient( ); HttpMethod method = new GetMethod("http://www.apache.org"); for( int i = 0; i < 3; i++ ) { setHeaders(method); client.executeMethod(method); processResults(method); method.releaseConnection( ); method.recycle( ); } } private void setHeaders(HttpMethod method) { method.setRequestHeader(new Header("If-None-Match", entityTag ) ); method.setRequestHeader(new Header("If-Modified-Since", lastModified ) ); } private void processResults(HttpMethod method) throws HttpException { if(method.getStatusCode( ) == HttpStatus.SC_NOT_MODIFIED ) { System.out.println( "Content not modified since last request" ); } else { entityTag = retrieveHeader( method, "ETag" ); lastModified = retrieveHeader( method, "Last-Modified" ); System.out.println( "Get Method retrieved content." ); System.out.println( "Entity Tag: " + entityTag ); System.out.println( "Last Modified: " + lastModified ); } } private String retrieveHeader( HttpMethod method, String name ) throws HttpException { HeaderElement[] header = method.getResponseHeader("ETag"). getElements( ); String value = ""; if(header.length > 0) { value = header[0].getName( ); } return value; } }
Example 11-1 requests the
same page three times; the first request retrieves the content, and the
second and third requests contain the headers for a conditional HTTP
GET. Because the Apache homepage remains unchanged throughout this
example, the content of http://www.apache.org is retrieved
only once. This example uses the headers in the first response to
populate the If-None-Match
and
If-Modified-Since
headers for the
second and third requests:
Request 1. Get Method retrieved content. Entity Tag: "2da794a-2d0d-998ebc80" Last Modified: Wed, 14 Apr 2004 05:53:38 GMT Request 2. Content not modified since last request Request 3. Content not modified since last request
This first request is similar to a regular HTTP GET, and if you examine the contents of the first request and response, you will see that the server's response contains two headers:
Last-Modified: Wed, 05 May 2004 02:51:59 GMT ETag: "a06d2-76-829811c0"
Example 11-1 takes the
values of these two response headers and stores them in the entityTag
and lastModified
variables. When the next request
is made, the values of these two variables are used to populate the
conditional headers If-None-Match
and If-Modified-Since
in the
setHeaders()
method. These request
headers are present in the second request for the same resource:
GET / HTTP/1.1 If-None-Match: "2da7807-31a8-e1eeb400" If-Modified-Since: Tue, 11 May 2004 23:57:04 GMT User-Agent: Jakarta Commons-HttpClient/3.0final Host: www.apache.org
When the server receives these conditional headers, it will check
to see if the resource has been modified. If the resource has been
modified, the resource will have a different modified date and different
entity tag value. If the resource has not been modified, the server will
respond to HttpClient
with a 304 Not Modified
response code:
HTTP/1.1 304 Not Modified Date: Sat, 15 May 2004 16:59:23 GMT Server: Apache/2.0.49-dev (Unix) ETag: "2da7807-31a8-e1eeb400" Expires: Sun, 16 May 2004 16:59:23 GMT Cache-Control: max-age=86400
The ETag
header is known as an entity
tag
, and it is similar to a hash code for a resource served
by a particular web server. Different servers have different algorithms
for creating an ETag
header; for
example, the Apache HTTPD server has a configuration directive, which
allows you to base an ETag
on a
configurable set of file attributes, such as size, i-node number, and
modified time. Consider an ETag
to
be a unique identifier for a particular version of a resource; if this
header changes, the corresponding resource has been altered.
Entity tags (the ETag
header)
are described in sections 3.11 and 14.19 of RFC 2616 (http://www.zvon.org/tmRFC/RFC2616/Output/index.html).
The Apache HTTPD server can be configured to use different file
attributes when creating an ETag
header. For more information about configuring the Apache HTTPD
server
via
the FileETag
directive, see the
documentation of Apache's core features (http://httpd.apache.org/docs-2.0/mod/core.html#fileetag).