Chapter 2. Working with Cookies

Cookies? Seriously?

I feel almost ashamed to be speaking about cookies in a modern web development book in 2015, but they are the oldest, and most stable, form of client-side storage available to developers today. They are certainly not the best method, and I’d almost never recommend using them, but they are an option and you may be forced to use (or modify) code that makes use of them at some point in the future.

Cookies were introduced in 1994 in a beta version of Netscape. They worked by using header values sent along with HTTP requests and responses. As you may know, whenever your browser requests a resource, a set of headers will be sent along with the request. Those headers include various types of data, including information about the browser and what form of data it wants. On the flip side, the server will also send headers back. Basically, every time you see a web page rendered in your browser, there was a set of headers that were also sent that you don’t see. (You certainly can see them using browser tools. They aren’t hidden as in “impossible to see,” just hidden from view by default.)

Cookies are sent using HTTP headers, specifically the “Cookie” HTTP header, and are sent by the browser to the server and sent to the browser from the server. Right away you should see a problem with that. If one of the benefits of using client-side storage is that we don’t have to send data over the wire, doesn’t sending cookies back and forth negate that benefit? Absolutely. This is one more reason why I typically won’t recommend using cookies.

By default, the browser makes no limit on the number of cookies it can have. In the past, there was a limit of 20 cookies per domain, but modern browsers seem to have removed that limit. (As an aside, I once set over 400 cookies in a Chrome browser and it worked just fine. However, my web server started throwing errors when requests were made. So in this case, it was an issue of the web server having a limit, not the browser itself. But please don’t use 400 cookies.) Research, or in other words, Googling, seems to indicate that a limit of 50 cookies per domain is safe at a total of 4 KB. That isn’t a lot of space for cookie values, which hinders their real-world usage.

Cookies are unique per domain. This means that a cookie value set on foo.com will not be available on goo.com. This is good since you wouldn’t want some other site to interfere with your usage on your own site. Cookies can be made to be unique in subdomains as well. So, for example, maybe app.foo.com is a unique subdomain of the Foo website. You can create cookies that are readable only on app.foo.com as well as cookies that would be available to www.foo.com and app.foo.com.

To make things even more complex, you can also create cookies that are valid only for a particular path. So, instead of app.foo.com, you may want to create cookies available just to foo.com/app.

Finally, you can create cookies that work only on the secure (https) version of your site. Obviously which of these options you use will depend on whatever your application is doing and where you think cookie values need to be present.

Along with where cookies are available, you can also specify how long they are available. Your options are:

  • Cookies that last for the current session (basically until the browser is closed)

  • Cookies that will last forever

  • Cookies that live for a certain amount of time

  • Cookies that expire after a particular time

Working with Cookies

Cookies do not have an API. To work with them, you simply access the document.cookie object in your code. So for example, to create a cookie, you could do this:

document.cookie = "nameOfCookie=value";

In the preceding example, I created a cookie called nameOfCookie and defined it as value. You use a "name=value" format to define the name and value all at once. Here is a real example:

document.cookie = "name=Raymond";

In the previous example, I simply set a cookie called name to the value Raymond. Values must be URL-safe, which means if you are doing anything dynamic, you’ll want to use a helper function like encodeURIComponent.

name = "Raymond Camden";
document.cookie = "name=" + encodeURIComponent(name);

So far, so good. But here’s where things get a bit wonky. You may be wondering how you would set multiple cookies. If you literally set document.cookie multiple times, it just works. So, for example:

document.cookie = "name=Raymond";
document.cookie = "age=43";

In this code sample, we’ve actually created two cookies, not one. That just feels plain wrong to me, but you’ll have to just roll with it.

So that’s how you create a cookie with a value, but what about all the metadata I mentioned—like defining where a cookie is available and how long it lasts? The format for appending metadata in a cookie is to use a semicolon after the value. Here is an example:

document.cookie = "name=Raymond; expires=Fri, 31 Dec 9999 23:59:59 GMT";

This example specifies when the cookie expires. We can further expand it by specifying that it works only on a subdomain:

document.cookie = "name=Raymond; expires=Fri, 31 Dec 9999 23:59:59 GMT; 
domain=app.foo.com";

You get the idea. When you don’t specify metadata like this, cookies will default to the current domain, the current path (probably not what you want), and an expiration in the current session.

Reading Cookies

Reading cookies is somewhat easier—depending on how comfortable you feel about string parsing. There is no API to get “a” cookie. Instead, you can simply read document.cookie. Doing so will give you all the cookies set for a particular site. Here is the document.cookie value from CNN:

"_cb_ls=1;
_chartbeat2=Dlxk2YDHxyg1BXCry6.1426601000831.1439508384927.0000000000000001;
Akamai_AnalyticsMetrics_clientId=89E881222E0BD593DF2468758F328F689C36BAC1;
octowebstatid=16ppgnhrso5f2frjuvq5; ug=55cd27810eb00b0a3c6ac33c7d05339d; ugs=1;
__CG=u%3A2449373858398994400%2Cs%3A72001958%2Ct%3A1439508379253%2Cc%3A1%2Ck%3
Awww.cnn.com/19/19/54%2Cf%3A0%2Ci%3A0; __CT_Data=gpv=10;
__gads=ID=3d001e8bba3c7c6d:T=1426601001:S=ALNI_MYWNYv1SRt0tx7LQ2AzdSESOBygNA;
__vrf=1439508379290061VnNeHVWPiIjkcWMeUjRWpppwsPktE;
grvinsights=a5a942f8e7c604d573496053d63f590c; optimizelyBuckets=%7B%7D;
optimizelyEndUserId=oeu1426600996913r0.5135214943438768;
optimizelySegments=%7B%22170962340%22%3A%22false%22%2C%22171657961%22%3A%22
safari%22%2C%22172148679%22%3A%22none%22%2C%22172265329%22%3A%22direct%22%7D;
RT=sl=1&ss=1439508375405&tt=9387&obo=0&bcn=%2F%2F36f11e49.mpstat.us%2F&sh=1439
508384794%3D1%3A0%3A9387&dm=cnn.com&si=5be398d8-bb51-42ea-8128-6d4251e47ada;
 s_cc=true;s_fid=5324AC5D0F8323AB-3F26DEB602CBB276; s_ppv=13; s_sq=%5B
%5BB%5D%5D;s_vi=[CS]v1|2A841A13051D0B97-400001280000490C[CE]; tosAgreed=true"

If that seems like a mess, you’re absolutely correct. Reading an individual cookie would mean parsing the string into components separated by a semicolon. Also note that you do not have access to any metadata. There is no way to get this information via the document.cookie value. It wouldn’t be too difficult to parse the string, but you really don’t need to do that. Toward the end of this chapter I’ll show you a great little library that makes working with cookies easier.

Deleting Cookies

To delete a cookie, you can simply set a cookie with an expiration in the past:

document.cookie = "name=Raymond; expires=Thu, 01 Jan 1970 00:00:00 GMT";

Technically the value doesn’t matter, but the name must match the name of the cookie you want to delete.

Demos

Now that you’ve seen the basics of working with cookies, let’s look at a simple demo. As I mentioned, you probably don’t want to build cookie parsing code yourself. Instead, you should use one of the many libraries out there. For our demo, we’ll use a simple (and excellent) free library from the  Mozilla Developer Network (MDN). You can find this code (along with even more information on cookies) at https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie. The library has methods for:

getItem
Gets a cookie
setItem
Sets a cookie (including expiration, path, domain, etc.)
removeItem
Deletes a cookie
hasItem
Checks if a cookie exists
keys
Returns the names of all the cookies

The MDN code has been saved in a file called cookies.js. This is available along with the rest of the code for this book. Our first example, test1.html, will simply use a cookie to count how many times you’ve visited the site (Example 2-1).

As a quick aside, all examples in this book will assume (and require) that you run them from a local web server and not just by opening the file in your browser. If you don’t have a local web server installed, consider a simple tool like httpster for a quick way to set up a development web server. (But promise me you’ll install a proper web server later. You are a web developer, right?)

Example 2-1. test1.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Cookie Test One</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <script type="text/javascript" src =
    "http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript" src="cookies.js"></script>
</head>

<body>

    <div id="resultDiv"></div>

    <script>
    $(document).ready(function() {

        //initial value
        var visited = 0;

        //Check to see if we have the cookie...
        if(docCookies.hasItem("visited")) {
            //and get it
            visited = docCookies.getItem("visited");
        }

        visited++;

        //update
        docCookies.setItem("visited", visited);

        $("#resultDiv").text("You have visited this site "+ visited +
             " times.");

    });
    </script>

</body>
</html>

Starting from the top, you can see a fairly typical document.ready block from the friendly jQuery library. I begin by setting an initial value for a variable called visited. If the cookie library says I have a cookie called visited, I then update the variable with the cookie’s value. I then increment this value by one, store it back, and then display it in the browser. By default, this cookie will exist only for the current session, so let’s improve it in test2.html (Example 2-2).

Example 2-2. test2.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Cookie Test Two</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <script type="text/javascript" src =
    "http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript" src="cookies.js"></script>
</head>
<body>

    <div id="resultDiv"></div>

    <script>
    $(document).ready(function() {

        //initial value
        var visited = 0;

        //Check to see if we have the cookie...
        if(docCookies.hasItem("visited2")) {
            //and get it
            visited = docCookies.getItem("visited2");
        }

        visited++;

        //update
        docCookies.setItem("visited2", visited, Infinity);

        $("#resultDiv").text("You have visited this site "+ visited +
            " times.");

    });
    </script>

</body>
</html>

In this version, we’ve made two changes. First, our cookie is now visited2. Normally I’d use the same name as before, but we want to differentiate between the two cookies while testing. The second change was to modify the setItem call. We’ve used an expiration value of Infinity. This creates a cookie that will last forever. Now that page will accurately reflect how many times it has been visited by a particular user regardless of whether the user is visiting during the same browser session.

So far our demos have been pretty simple, so let’s take it up a notch. We can use cookies to remember when a user has last visited the site. Based on the user’s last visit, we can either:

  • Greet a new user who has never been here before.

  • Provide a special message to someone who hasn’t been here in a while—for example, mentioning cool new features.

  • Simply welcome a user who has visited often.

Let’s look at the code (Example 2-3) and then I’ll walk you through how it works.

Example 2-3. test3.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Cookie Test Three</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <script type="text/javascript" src =
    "http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    <script type="text/javascript" src="cookies.js"></script>
</head>
<body>

    <div id="resultDiv"></div>

    <script>
    $(document).ready(function() {

        var $resultDiv = $("#resultDiv");

        //Is this a brand new user?
        var newUser = true;
        //How many days since last visit
        var daysSinceLastVisit;

        //Check to see if we have the cookie...
        if(docCookies.hasItem("lastVisit")) {
            newUser = false;
            //do some math to find out how long it has been
            var lastVisit = docCookies.getItem("lastVisit");
            var now = new Date();
            var lastVisitDate = new Date(lastVisit);
            //credit: http://stackoverflow.com/a/3224854/52160
            var timeDiff = Math.abs(now.getTime() - lastVisitDate.getTime());
            var daysSinceLastVisit = Math.ceil(timeDiff / (1000 * 3600 * 24));
        }

        //Set to now
        docCookies.setItem("lastVisit", new Date(), Infinity);

        if(newUser) {
            $resultDiv.text("Welcome to the site!");
        } else if(daysSinceLastVisit > 20) {
            $resultDiv.text("Welcome back to the site!");
        } else {
            $resultDiv.text("Welcome good user!");
        }

    });
    </script>

</body>
</html>

We begin by setting up two variables, newUser and daysSinceLastVisit. The first will simply be a Boolean we can check to determine if the user is brand new, while the latter will report on how many days it has been since the user’s last visit.

If a cookie, lastVisit, exists, we get it and then create a Date variable out of the value. From that we can then use some simple math to figure out how many days it has been since the user’s last visit.

Next, we set the cookie value for lastVisit to the current time.

That’s the core of the logic; we then simply spit out a message based on one of the three states just mentioned. In this demo, the value 20 is used to determine that it has been too long since the user visited. Obviously this value is arbitrary.

Inspecting Cookies Within Developer Tools

Modern browsers provide excellent developer tools that make it easier to inspect and check your use of cookies. In Firefox, you can see cookies if you enable the Storage tab (it may not be visible by default). Once it’s enabled, you can view your current cookies (see Figure 2-1). Firefox does not allow you to modify cookies, just view them.

Chrome  will show you a site’s current cookies in the Resources tab (Figure 2-2). You can delete cookies here, but not edit them.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.14.240.252