Basic knowledge
1) What is "last-modified "?
When the browser requests a URL for the first time, the server returns 200, and the content is the resource you requested, at the same time, there is a last-modified attribute to mark the last modification time of this file on the service end. The format is similar to this:
Tue, 24 Apr 2012 13:53:56 GMT
When the client requests this URL for the second time, according to the HTTP protocol, the browser will send the IF-modified-since header to the server, asking if the file has been modified after the time:
If-modified-since: Tue, 24 Apr 2012 13:53:56 GMT
If the resources on the server are not changed, the HTTP 304 (not changed.) status code is automatically returned and the content is blank, which saves the amount of data transmitted. When the server sideCodeWhen the server is changed or restarted, the resource is re-issued, and the returned result is similar to the first request. This ensures that resources are not repeatedly sent to the client, and that the client can obtain the latest resources when the server changes.
2) What is "etag "?
The HTTP specification defines etag as the object Value of the requested variable ". In other words, etag is a token that can be associated with web resources ). A typical web resource can be a Web page, but it may also be a JSON or XML document. The server is solely responsible for determining what the mark is and its meaning, and transmitting it to the client in the HTTP Response Header. The following is the format returned by the server:
"9077da2dec72bbb7151a6579fa214de0"
The query update format of the client is as follows:
"9077da2dec72bbb7151a6579fa214de0"
If etag does not change, status 304 is returned and no result is returned, which is the same as last-modified.
How does last-modified and etags help improve performance?
Smart developers will use the HTTP header of the last-modified and etags requests together, so that the cache of the client (such as the browser) can be used. Because the server first generates the last-modified/etag mark, the server can use it later to determine whether the page has been modified. Essentially, the client sends this mark back to the server and requires the server to verify its (client) cache.
The process is as follows:
1. The client requests a page ().
2. The server returns to page A and adds a last-modified/etag to page.
3. The client displays the page and caches the page together with last-modified/etag.
4. The customer requests page a again and passes the last-modified/etag returned by the server in the last request to the server.
5. The server checks the last-modified or etag and determines that the page has not been modified since the last client request. The server returns the response 304 and an empty response body.
Correct use of etag and expires identification can make the page cache more effective.
When the client sends a request for a URL for the first time through a browser, the browser will send the header (HTTP Request Header) to the server according to the HTTP protocol ), when the server responds with the HTTP reponse header, the server returns 200 in the following format:
HTTP/1.1 200 OK
Cache-control: public, Max-age = 1728000
Transfer-encoding: chunked
Content-Type: image/JPEG
Expires: Sun, 20 May 2012 16:26:22 GMT
Last-modified: Tue, 24 Apr 2012 13:53:56 GMT
Etag: "9077da2dec72bbb7151a6579fa214de0"
Server: Microsoft-Microsoft IIS/7.5
X-ASPnet-version: 4.0.30319
X-powered-by: ASP. NET
Date: Mon, 30 Apr 2012 16:26:22 GMT
When the client requests this URL for the second time, according to the HTTP protocol, the browser will send an HTTP request header to the server. The server responds and records that the relevant record property Tag file has not been changed, the server returns 304, which is directly read from the cache:
HTTP/1.1 304 not modified
Cache-control: No-Cache
Pragma: No-Cache
Expires:-1
Server: Microsoft-Microsoft IIS/7.5
X-ASPnet-version: 4.0.30319
X-powered-by: ASP. NET
Date: Mon, 30 Apr 2012 16:30:06 GMT
The implementation code of Asp.net web API is as follows:
// Get/img/2012031023134242.png
[Httpget]
Public httpresponsemessage get ([fromuri] string filename)
{
Httpresponsemessage response = new httpresponsemessage ();
Export fsdirectory FS = new export fsdirectory (new export fsdirectoryparameters () {connectionstring = This. connectionstring });
Repeated gridfsfileinfo fileinfo = FS. getfileinfo (filename );
If (fileinfo = NULL)
{
Throw new httpresponseexception ("the file does not exist.", httpstatuscode. notfound );
}
String etag = string. Format ("\" {0} \ "", fileinfo. MD5 );
VaR tag = request. headers. ifnonematch. firstordefault ();
If (request. headers. ifmodifiedsince. hasvalue & tag! = NULL & tag. Tag = etag)
{
Response. statuscode = httpstatuscode. notmodified;
}
Else
{
Memorystream responsestream = new memorystream ();
Repeated gridfsstream GFS = fileinfo. openread ();
bool fullcontent = true;
If (this. Request. headers. range! = NULL)
{< br> fullcontent = false;
// currently we only support a single range.
rangeitemheadervalue range = This. request. headers. range. ranges. first ();
// From specified, So seek to the requested position.
If (range. From! = NULL)
{
GFS. Seek (range. From. Value, seekorigin. Begin );
// In this case, actually the complete file will be returned.
If (range. From = 0 & (range. To = NULL | range. To> = gfs. Length ))
{
GFS. copyto (responsestream );
Fullcontent = true;
}
}
If (range.! = NULL)
{
// 10-20, return the range.
If (range. From! = NULL)
{
Long? Rangelength = range. To-range. From;
Int length = (INT) math. Min (rangelength. Value, gfs. Length-range. From. value );
Byte [] buffer = new byte [length];
GFS. Read (buffer, 0, length );
Responsestream. Write (buffer, 0, length );
}
//-20, return the bytes from beginning to the specified value.
Else
{
Int length = (INT) math. Min (range. to. Value, gfs. Length );
Byte [] buffer = new byte [length];
GFS. Read (buffer, 0, length );
Responsestream. Write (buffer, 0, length );
}
}
// No range.
Else
{
// 10-, return from the specified value to the end of file.
If (range. From! = NULL)
{
If (range. From <gfs. length)
{
Int length = (INT) (GFS. Length-range. From. value );
Byte [] buffer = new byte [length];
GFS. Read (buffer, 0, length );
Responsestream. Write (buffer, 0, length );
}
}
}
}
// No range header. Return the complete file.
Else
{
GFS. copyto (responsestream );
}
GFS. Close ();
Responsestream. Position = 0;
Response. statuscode = fullcontent? Httpstatuscode. OK: httpstatuscode. partialcontent;
Response. content = new streamcontent (responsestream );
Response. content. headers. contenttype = new mediatypeheadervalue (fileinfo. contenttype );
Response. headers. etag = new entitytagheadervalue (etag );
Response. headers. cachecontrol = new cachecontrolheadervalue ();
Response. headers. cachecontrol. Public = true;
Response. headers. cachecontrol. maxage = timespan. fromhours (480 );
Response. content. headers. expires = datetimeoffset. Now. adddays (20 );
Response. content. headers. lastmodified = fileinfo. uploaddate;
}
Return response;
}