IntroductionWelcome| 00:04 | Hi! I'm Bill Weinman and I'd like to
welcome you to HTML5: Messaging and
| | 00:08 | Communication in Depth.
| | 00:09 | In this course we'll look at the
HTML5 messaging application programming,
| | 00:13 | interface including how messages work,
the same-origin policy, and effective
| | 00:19 | techniques for cross-origin scripting.
| | 00:21 | The HTML5 messaging API provides an
excellent tool for creating cross-origin
| | 00:27 | applications safely and effectively.
| | 00:29 | Learn how to use this powerful
technology in HTML5: Messaging and
| | 00:33 | Communication in Depth.
| | Collapse this transcript |
| Using the exercise files| 00:00 | If you have access to the exercise
files for this course, you can use them to
| | 00:04 | follow along with the lessons as I present them.
| | 00:07 | In order to follow along, you'll need to
upload these files to a server and edit
| | 00:11 | the files on the server
instead of on your workstation.
| | 00:14 | The technology presented in this
course will not work without a web server.
| | 00:18 | The examples in this course count on
documents being served from different
| | 00:22 | origins, so you must be able to set up
your server with at least two domains
| | 00:27 | using the same set of files.
| | 00:29 | It's a good idea to have a text editor
capable of editing over SFTP on a server.
| | 00:34 | I use the excellent BBEdit or its
free version, TextWrangler, on the Mac.
| | 00:39 | On the PC I use Notepad++, which is also
capable of editing on the server over SFTP.
| | 00:45 | Here in the exercise folders you'll find a
folder for the various chapters in the tutorial.
| | 00:50 | The files inside the folders are
generally organized by chapter, and many have
| | 00:54 | start and done files as a
beginning and ending place for that file.
| | 00:59 | You'll want to start with a working
copy of the start file, or a working copy of
| | 01:03 | the file from the previous movie, and
work with the copy so that you can start
| | 01:08 | over again with a fresh copy if you need to.
| | 01:11 | In the CSS folder, you'll find a simple CSS
file that is used for all of the examples.
| | 01:18 | Now I'm just going to page through
this for you for the benefit of those
| | 01:21 | who're typing this in.
| | 01:24 | If you do not have access to these
exercise files you may still follow along and
| | 01:28 | create files of your own.
| | Collapse this transcript |
|
|
1. OverviewOverview of HTML5 messaging| 00:00 | HTML5 messaging allows you to create
communication channels between objects and windows.
| | 00:06 | It's used by many of the other HTML5
APIs, and may even be used to communicate
| | 00:10 | between windows across domains.
| | 00:13 | HTML5 messaging is accomplished
by sending and receiving events.
| | 00:17 | An event object has a data member
which carries the message payload. The data
| | 00:22 | member may be a string or it may be an object.
| | 00:25 | Alternately, the data member may carry a
JSON payload in order to represent more
| | 00:30 | complex structured data.
| | 00:32 | Note that Internet Explorer will only
send strings, so you'll need to use JSON
| | 00:36 | for any structured data.
| | 00:38 | Listeners may be implemented in one of two ways.
| | 00:41 | IDL listeners use the familiar
onmessage = function syntax, and registered
| | 00:46 | listeners use the addEventListener method.
| | 00:50 | Keep in mind that depending on the
objects you're working with, one of these
| | 00:53 | methods may be supported better than the
other, or even at the exclusion of the other.
| | 00:58 | Senders are implemented with
a simple postMessage method.
| | 01:02 | It's very simple, and we'll discuss the
details as we use it later on in this course.
| | 01:06 | The event object itself has several
members that you'll be interested in.
| | 01:10 | The data member carries the message payload.
| | 01:13 | The origin member carries a string
representing the origin of the message--and
| | 01:17 | we'll get into detail with this later--
| | 01:20 | and the source member
carries a proxy window object.
| | 01:23 | HTML messaging is supported on all the
major platforms, with few differences.
| | 01:29 | Please note that while cross-domain
messaging works on Microsoft Internet
| | 01:33 | Explorer, it only works for frames;
it does not work between documents in
| | 01:37 | separate tabs or windows.
| | 01:39 | Also note again that Internet Explorer
will only send strings in the payload, so
| | 01:43 | you'll need to use JSON for any structured data.
| | 01:46 | HTML5 is simple to implement, but it
does have some dangers to look out for,
| | 01:51 | we'll cover these details
in the rest of the course.
| | Collapse this transcript |
| Security and the same-origin policy| 00:00 | Communicating across domains is a common
problem for web application developers.
| | 00:05 | Major browser vendors consistently
implement a security policy called the
| | 00:09 | same-origin policy.
| | 00:11 | This prevents a script from one site
from manipulating properties of a document
| | 00:15 | loaded from another site.
| | 00:17 | These different sites are called origins.
| | 00:20 | This important security policy is
effective in preventing session hijacking and
| | 00:24 | phishing attacks, and like most
effective security policies, it can be
| | 00:29 | frustrating at times, like when you
have a legitimate need to have scripts
| | 00:33 | communicate with each
other across different origins.
| | 00:36 | So what exactly is an origin?
| | 00:38 | An origin is made up of three components:
the protocol, the host, and the port.
| | 00:44 | If any of these three components are
different, the origins are different.
| | 00:47 | For example, if you have one document
at this URL and another document at this
| | 00:54 | URL, are they in the same origin?
| | 00:57 | These two URLs are in the same origin.
They have the same protocol, the same
| | 01:01 | hostname and they have the same port
number, which in this case is the default
| | 01:06 | port number, port number 80,
because none is specified.
| | 01:09 | This URL is also in the same origin.
| | 01:13 | The document itself is in a
subdirectory, but that doesn't change the origin.
| | 01:17 | The origin is not dependent on the
directories; it's dependent only on the
| | 01:20 | protocol, the hostname, and the port number.
| | 01:23 | This document, on the other
hand, is in a different origin.
| | 01:26 | You'll notice that the hostname
is different because it says blog.
| | 01:30 | instead of www. Even though that's the
third level of the domain, it's still significant.
| | 01:36 | Any difference in the hostname
will make a difference in the origin.
| | 01:42 | This one is also a different origin
because the protocol is different.
| | 01:45 | Here it has https instead of http.
| | 01:49 | And this one is also different. Even
though the protocol and the hostname are
| | 01:53 | the same, this one specifies a port
number that's different than port number 80.
| | 01:58 | So let's take a look at an example so
that we can see what happens when you try
| | 02:02 | to access an object across different origins.
| | 02:07 | Here I have two documents that are
loaded up at two different URLs that are on
| | 02:12 | two different origins.
| | 02:14 | First of all, let's take a look at the documents.
| | 02:17 | Especially for those of you who are
following along at home without the
| | 02:20 | exercise files, I'm just going to page
through this really quickly so that you
| | 02:24 | can see the whole thing.
| | 02:34 | And the same with the other document.
That one is crossDomainOneError, and
| | 02:38 | this one here is crossDomainTwoError, and
you'll notice that it's a little bit different.
| | 02:43 | Now there is a lot of support stuff in
these two documents, but for the most
| | 02:56 | part all they do is one loads up the
other in a frame and then it tries to
| | 03:01 | access the title from that other document.
| | 03:05 | So here it is, loaded up in a browser,
and they're on two different domains.
| | 03:09 | The outer document is loaded up from the host
| | 03:12 | one.3sn.net, and these are just a couple
of domains that I have that I use. And
| | 03:17 | the inside one is loaded
up from host two.3sn.net.
| | 03:21 | And you notice that the error message
comes up here that says, "Permission denied
| | 03:25 | to access property 'document'," and
the reason for that is right here.
| | 03:30 | Here we are, in document 2, and you'll
notice in the init function, it loads up
| | 03:34 | this variable windowOne from parent,
which is the window object from the parent
| | 03:39 | window that loaded up the frame.
| | 03:41 | Remember, this document is inside of a frame.
| | 03:44 | And then it tries to access the
document title from that parent document,
| | 03:50 | but it's in a different origin,
and so you end up with this error.
| | 03:55 | If instead I load them up from the
same origin--and I can do that by coming in
| | 04:02 | right here and just changing this hostname
and I'll explain this trickery in a moment here.
| | 04:08 | I'm just going to change it so that
it's loading up a document off of the exact
| | 04:11 | same domain and it's exactly the same document.
| | 04:14 | And when I reload--I'm going to press
Reload here--you'll notice that it works,
| | 04:18 | and it's actually able to get that parent title.
| | 04:20 | Now it's important that you understand
how I have this set up, and you're going to
| | 04:24 | need to do something like this in order
to efficiently play with these examples
| | 04:29 | and learn about the same-origin policy.
| | 04:31 | I'm a big proponent of learning by
experimenting and trying things and failing
| | 04:36 | and figuring out why.
| | 04:38 | So in order to do that, what you're
going to need is to setup where you have the
| | 04:41 | example files on a server--not on
your local machine on your Desktop, but on
| | 04:47 | a server that you're
accessing using domain names--
| | 04:50 | and on that server you have several
different domain names pointing at exactly
| | 04:55 | the same file system.
| | 04:57 | And so what I've done here is I have
a cloud server at Rackspace, and you
| | 05:01 | can use any of the cloud
server providers or whatever server you
| | 05:05 | have accessible to you.
| | 05:07 | And I've simply used a few domains,
and I've set up Apache so that those few
| | 05:11 | domains point at exactly the same file system.
| | 05:13 | So I have all these files up there once,
but they're actually accessible from
| | 05:17 | one.3sn.net and two.3sn.net and three.3sn.net.
| | 05:23 | Now in order to do this, you are of
course going to need to use your own server
| | 05:26 | and your own domain names. And you
really need to have some kind of a setup like
| | 05:30 | this in order to follow along
with the examples in this course.
| | 05:34 | So the HTML5 messaging API provides an
effective way to work around the same-
| | 05:39 | origin policy, so that you can communicate
with your own scripts on different origins.
| | 05:43 | We'll take a look at how this works
in detail in the rest of this course.
| | Collapse this transcript |
| An example application| 00:00 | This is a simple example application
that implements cross-origin messaging
| | 00:04 | using the HTML5 messaging API.
| | 00:07 | So you can see we have two documents
loaded up: one outside and one inside a frame.
| | 00:13 | And again, because Internet Explorer
won't even do this if they're in separate
| | 00:17 | tabs, I've had to use frames
for all of these examples.
| | 00:21 | But just know that you can do exactly
the same thing in tabs if you're using
| | 00:26 | Firefox or Chrome or
Safari or any other browser.
| | 00:30 | But that doesn't work in Internet Explorer.
| | 00:32 | So the way I have this set up is that
these two documents are hosted on a server
| | 00:38 | where the same file system is
accessible from different domains, and so they're
| | 00:42 | effectively in two different domains,
at least from the perspective of the
| | 00:45 | browser. And so the browser has its same
origin policy in place and it's treating
| | 00:51 | these as being from two separate origins.
| | 00:54 | So the outer document is on a host
called one.3sn.net, and the inner document is
| | 01:01 | on a host called two.3sn.net.
| | 01:03 | And you'll notice these timestamp log
messages tell you the sequence of how
| | 01:08 | things are happening.
| | 01:09 | Document one loads up and then as part of
its loading process, it loads up document two.
| | 01:15 | And document two comes along as soon
as it's loaded and it grabs the window
| | 01:19 | object for its parent and it sends a
message to its parent, and so it says over
| | 01:23 | here at 035 milliseconds,
"Message sent to windowOne."
| | 01:28 | And then at 036 milliseconds it says,
"Message from origin two.3sn.net."
| | 01:34 | And then there's the message, "this
is from windowTwo," and then it sends a
| | 01:37 | message right back to windowTwo at 037
milliseconds, and then we have a message
| | 01:43 | from origin one.3sn.net,
and this is from windowOne.
| | 01:49 | So here is an example of two
different documents in two different domains
| | 01:53 | sending data back and forth
across that same-origin policy barrier.
| | 01:58 | Let's take a look at the code.
| | 01:59 | First of all, I'm just going to page
through really slowly for those of you
| | 02:02 | who are typing it in.
| | 02:06 | This first document is called
crossDomainOne.html, and this is the document
| | 02:10 | loaded up at one.3sn.net.
| | 02:20 | And again, you'll see a lot of support
stuff in here that has more to do with the
| | 02:23 | rest of course than
perhaps this particular example.
| | 02:27 | And then crossDomainTwo.html is
loaded up on two.3sn.net, and this is the
| | 02:34 | document that gets loaded inside of the frame.
| | 02:46 | So taking a look first at
crossDomainOne.html, the init function gets called down
| | 02:53 | here at the bottom of the JavaScript.
This is a technique that I'll use a lot
| | 02:56 | window.onload = init. And so when it
gets that onload event, that means that the
| | 03:02 | document is all loaded up, and it calls
this init function. And one of the first
| | 03:07 | things that it does is it grabs the
frame element and it sets its source to
| | 03:12 | URLTwo, and that loads the frame.
| | 03:14 | So the frame element is down here in the
HTML, and you notice it does not have a source.
| | 03:19 | And up here at the top of the
JavaScript you'll see URLTwo, here on line 36, and
| | 03:27 | that's the URL that gets
loaded up for the second document.
| | 03:30 | And I did this because it's a convenient
way to be able to change the URL in one place.
| | 03:36 | That actually makes it
easier to experiment with it.
| | 03:39 | Like for instance, if I wanted to change
it to three.3sn.net--and I'll save that
| | 03:45 | and go and load this up on the
browser--it'll do it, and it gives me an error
| | 03:50 | message, "message from un-
trusted origin three.3sn.net."
| | 03:54 | Because well, we'll get into the
details of how this is working later on, but
| | 03:57 | we're actually specifying the origin
of the documents that we're sending and
| | 04:02 | receiving messages from, so
that we can't easily be spoofed.
| | 04:06 | So I'll just change that back.
| | 04:07 | What you're going to need to do is
every time we bring up one of these examples,
| | 04:12 | you're going to need to come in here in
both of these documents you're going to
| | 04:14 | need to change these variables to
match the origin and the URLs that you're
| | 04:20 | actually using for your documents.
| | 04:22 | These will not work on your
servers if you've got my URLs in here.
| | 04:26 | And so in the document that goes in the
outer window, in the One document--and it
| | 04:31 | is pretty much always going to be on
the same line numbers, 35 and 36--you're
| | 04:35 | going to change the
origin for Two and URL for Two.
| | 04:38 | And then likewise, for the Two
document, you'll see that there is an origin
| | 04:44 | around line number 21.
| | 04:45 | The line numbers might move a little
bit here and there, but for the most part
| | 04:48 | they're going to be very close or
exactly the same throughout the course.
| | 04:53 | So we'll be using this very
simple example--I'll reload it here
| | 04:56 | to get ride of the error message--
throughout this course to demonstrate the various
| | 05:01 | techniques that we're using to make this work.
| | 05:03 | And you can see that it's pretty
simple in implement, and we'll be looking at
| | 05:06 | more details as we go through the course.
| | Collapse this transcript |
|
|
2. Event ListenersRegistering a listener| 00:00 | The first step to implementing HTML5
messaging is to register a listener.
| | 00:05 | This is done with the addEventListener
method of the object you want to listen to.
| | 00:09 | So what I have here is a working copy
of listener-one-start.html and working
| | 00:16 | copy of listener-two-start.html.
| | 00:19 | I have named them both -working. And
these are in the Chap02 folder of the
| | 00:25 | exercise files, and I've loaded them up on
my server so that we can test them there.
| | 00:30 | And the first thing that I need to do
is I need to come down here to lines 35
| | 00:35 | and 36 and make sure that these match.
| | 00:38 | So I'm in listener-one-working, and so I
need the origin for the listener-two, and
| | 00:45 | I need the URL for listener-two.
| | 00:47 | Now the origin is just this. It's the
protocol :// and the domain name and a
| | 00:55 | port, if you're using one and
probably not--that's very rarely done.
| | 01:00 | The URL, in this case I need to change
the word start over here to be working,
| | 01:05 | so that it loads up the right version
of the file. And I just pressed Save and
| | 01:09 | you saw a little dialog
box come up while it saved.
| | 01:12 | I'm actually editing directly on the server.
| | 01:15 | My editor will do that over SFTP, and
I strongly recommend that you have an
| | 01:19 | editor that does that.
| | 01:20 | I'm using TextWrangler on a Mac here. At
home I use BBEdit, which is the pay-for-
| | 01:24 | it version of
TextWrangler. TextWrangler is free.
| | 01:27 | And if you're on a PC you can use
Notepad++, which has that feature as well.
| | 01:32 | Now if you don't change this, the
danger is that you'll load up a different
| | 01:35 | version of the same file and it will
look like it's working, but you will
| | 01:38 | make changes to that file and nothing
changes on the screen, and you end up
| | 01:42 | pulling your hair out.
| | 01:43 | So I strongly recommend that you start
each one of these lessons by making sure
| | 01:48 | that you have these two things
correct in both of the files.
| | 01:51 | So this is in the -one file. And if I
bring up the -two file, come down here to
| | 01:57 | line 21, I'll see the same thing.
| | 01:59 | This just has the origin; it doesn't
actually need the URL of the -one file. And
| | 02:05 | so it's got the originOne, and you
want to make sure that that matches the
| | 02:08 | origin that you're using.
| | 02:11 | So let's just take a quick page-through of
these files so that those who are typing
| | 02:16 | along at home can do so.
| | 02:26 | So that's listener-one-working.html, and
this is listener-two-working.html. These
| | 02:34 | of course are copies of the -start files.
| | 02:37 | I strongly recommend you work with
copies, that you don't work with the -done
| | 02:41 | files, that you just start with the -start
files and work with copies. And that way
| | 02:47 | if you get stuck or lost, you can make a
fresh copy and work from there. All right!
| | 02:54 | So now we got our files copied, our files
typed in, and we're going to get to work.
| | 02:59 | The first thing we want to do in
implementing a listener is to write the
| | 03:03 | function that's going to handle the
message event, and that function is going to
| | 03:07 | be called handleMessage. And it gets an
event object as its sole parameter, and
| | 03:18 | the first thing that it
does is it tests the origin.
| | 03:20 | The event object has an origin
member, so it says if (event.origin ==
| | 03:26 | originTwo). And you notice originTwo up
here has that string in it, the origin
| | 03:35 | of the -two document.
| | 03:37 | And I'm just going to go ahead and
write the else right now, because this is a
| | 03:41 | condition that we want to be concerned with.
| | 03:44 | If the origin does not match, you want
to do something other than actually use
| | 03:50 | that data, and so I'm just
going to display an error message.
| | 03:52 | I am going to call my display error
function, which you can find down
| | 03:56 | below in the Utilities section.
| | 03:59 | My error message will be informative.
You don't necessarily want to do this in
| | 04:02 | production, be informative, you might
want to do something even nastier in
| | 04:06 | production. But I'm just going to say,
"message from untrusted origin," and I'm going
| | 04:14 | to say what that untrusted origin is.
| | 04:18 | So we can test it, and we can play around
with it, and we can know exactly what's going on.
| | 04:22 | Now the next thing I want to do is I
want to test if I have a windowTwo object.
| | 04:27 | If I don't, I'm going to grab it from the source.
| | 04:29 | So I'm going to say, if not windowTwo.
And you notice that windowTwo up here is
| | 04:36 | defined as null, and so if it's still
null, I'm going to assign it from the
| | 04:42 | event. windowTwo = event.source.
| | 04:48 | So the source member of the event
object has that. It's actually a window
| | 04:52 | proxy, but it works just like the
window object, and so you don't even need to know that it's not.
| | 04:56 | Now I'm going to log a message. I
have this lovely little log method that
| | 05:00 | displays those log messages on the
screen. And I'm going to say message from
| | 05:04 | origin, and I'm going to give the event.origin.
| | 05:11 | You can see what that looks like.
And then I'm going to log the data. And that's
| | 05:21 | our handleMessage function.
| | 05:24 | Now all I need to do is register it. And
I come down here into init, and you
| | 05:27 | remember that init gets assigned, it
gets called, because it's assigned to the
| | 05:32 | onload handler for the whole window.
| | 05:34 | So once the page has
completely loaded, then we call init.
| | 05:39 | So the first thing I'm going to
do in init is I'm going to add the
| | 05:41 | eventListener, window.addEventListener,
and it's for the message event, and it's going
| | 05:50 | to called the handleMessage function.
And then it gets this other parameter, which
| | 05:56 | is false, which has to do with the way
that messages propagate in the DOM, and
| | 06:01 | it's always going to be false.
| | 06:04 | So I'll go ahead and I'll save this.
I'm just pressing Command+S here on
| | 06:07 | the Mac. And then we can over to the
listener-two-working, and we're going to do
| | 06:13 | the same kind of stuff.
| | 06:14 | I am going to come down here and make
sure that our origin is correct there on
| | 06:17 | line 21, and then I'm going to go ahead
and create a handleMessage function. And
| | 06:30 | actually, if you want to, because
laziness is a virtue, I will just copy and
| | 06:35 | paste this from the other one and just edit it.
| | 06:39 | So our origin is going to be originOne.
| | 06:44 | We don't need to test for windowTwo or
even for windowOne, because we're not
| | 06:47 | sending messages back--at least not
from this function. And the rest of this
| | 06:51 | is exactly the same.
| | 06:53 | Then we come down here into the init
function and we add our eventListener. And
| | 07:01 | actually, this isn't used yet.
We can go ahead and delete that line.
| | 07:05 | So I'm saving the file and we
have now registered our listeners.
| | 07:10 | When we run this in the browser,
listener-one-working, we see that it's running properly.
| | 07:16 | It's not really sending any messages yet--
we'll get to that in the next movie--
| | 07:20 | but you can see for now that it's really
a straightforward process to register a
| | 07:23 | listener: you just create the message
handler and then you pass the function
| | 07:28 | reference to addEventListener.
| | 07:29 | In the next movie, we'll go ahead
and send some messages back and forth.
| | Collapse this transcript |
| Sending messages to a listener| 00:00 | Sending messages to a listener is
simply a matter of calling the postMessage
| | 00:04 | method on the target window object.
| | 00:07 | So here I have a working copy of
sender-one-start, and I named it
| | 00:13 | sender-one-working.html, and this is in
the Chap02 folder of the exercise files
| | 00:19 | on my server. And over here I have
sender-two-working.html, which is a working
| | 00:26 | copy of sender-two-start.html and
I'm also editing that on my server.
| | 00:33 | So the first thing I'm going to do is
I'm going to page through this, for those
| | 00:36 | of you who are typing it in all.
| | 00:41 | This is actually the place where we left
off in the last exercise, so if you did
| | 00:46 | the last exercise, you already have this file.
| | 00:53 | So that's the sender-one, and this is sender-two.
| | 01:14 | I'm just noticing that this time
function goes off the end of the screen there
| | 01:17 | just a little bit. So you can see
what that is. It's just got one little
| | 01:22 | character off the end of the screen there.
| | 01:25 | So now the next thing we want to do is
we want to make sure that we have these
| | 01:29 | two variable correct, the origin and the URL.
| | 01:32 | So in sender-one on line 35 and 36,
you want to make sure that these match
| | 01:38 | exactly. And you notice here it says
listener-two-working, because that's left
| | 01:42 | over from the last time, so I'm going
to type in here sender-two-working. And
| | 01:49 | the rest of this is correct, so I'm
going to press Command+S to save and then
| | 01:53 | look over at sender-two and do the same
thing here on line 21. You just want to
| | 01:59 | make sure that that is the
origin for your opposite file.
| | 02:05 | So while we're in sender-two, we're
going to ahead--because sender-two is the
| | 02:08 | first one that actually gets ready to
send a message, because you remember,
| | 02:13 | sender-one loads up sender-two, and so
sender-one doesn't actually have a window
| | 02:19 | object for sender-two until
sender-two sends it a message.
| | 02:22 | The first thing that sender-two has
to do is it needs to send a message to
| | 02:26 | sender-one to let it know
that it finished loading.
| | 02:29 | So I'm going to come down here in init.
I'm actually going to start with a
| | 02:33 | comment and say, "send a message to
the parent to let it know that windowTwo
| | 02:41 | has finished loading."
| | 02:46 | And so I'm going to make a local copy of
variable for windowOne because I'm not
| | 02:52 | actually going to use this outside of
here; otherwise, I could make it global.
| | 02:58 | There wouldn't be any harm in it. And
I'm going to assign it to that parent.
| | 03:03 | Because we have a parent object
already--this got loaded up by the parent--so
| | 03:07 | we can just load parent and get that
window object as easily as that. And then
| | 03:11 | I can say windowOne.postMessage--it's
really that simple--and give it the
| | 03:18 | message and originOne. And so in the message
here I'm just going to say, "this is from windowTwo!"
| | 03:30 | And then we'll log it that we've done something.
| | 03:33 | You know when I'm developing or
experimenting or learning about something, I like
| | 03:37 | to do a lot of logging, and it tells
me exactly what's going on and in what
| | 03:41 | sequence, and it helps me to keep track
of what I'm doing and what I'm learning.
| | 03:46 | "message sent to windowOne."
| | 03:48 | All right, so I'm going to press
Command+S to save this on the Mac, and we're
| | 03:53 | going to go ahead and run it.
| | 03:54 | Now we've only changed sender-two.
We have not changed sender-one, except to
| | 03:58 | make it load up the right thing, but
I'm still going to start with loading up
| | 04:03 | sender-one-working, because that
loads the frame for sender-two.
| | 04:06 | So I'm going to click on
sender-one-working, and there we go.
| | 04:11 | The outer one is sender-one, and the
inner one is sender-two. And you notice here
| | 04:16 | it says, "message sent to sender-one."
| | 04:18 | As soon as it loads up, it sends a
message to sender-one, and sender-one has
| | 04:22 | this message from origin, and there is the
origin of two.3sn.net, and this is from windowTwo.
| | 04:29 | So windowOne loads up windowTwo.
windowTwo loads up, and the first thing it
| | 04:34 | does is it sends a message back to
windowOne to let it know where it is, and
| | 04:37 | now windowOne actually has a window object
for windowTwo. It didn't have that before.
| | 04:43 | So now we can go back here into
windowOne, sender-one-working.html, and here on
| | 04:50 | our handleMessage function, you see
where we have the message from origin,
| | 04:54 | and that's this message right here. And there
is the origin where it came from, two.3sn.net.
| | 05:00 | So that's working. And we log the
event data, and that's this message here,
| | 05:05 | "this is from windowTwo."
| | 05:07 | And so now what we can do, you see
this message here that says, "if not
| | 05:10 | windowTwo, windowTwo = event.source,"
so we did not have a windowTwo before--
| | 05:15 | remember, it's initialized to null--and
so now we have it, because event.source
| | 05:19 | gives us that windowTwo object.
| | 05:22 | So now we can just come down here, we can say
windowTwo.postMessage (this is from windowOne! and originTwo).
| | 05:35 | You have to give it the origin of the
object that you're sending it to. And then
| | 05:41 | we'll log a message, and we'll save
that with Command+S. Now we're going to go
| | 05:51 | ahead and we're going to send a message
back to windowTwo. So I'm going to press
| | 05:55 | reload up here, and there we have it,
"message send back to windowTwo."
| | 06:01 | And then windowTwo has a message from
origin, and there's the one.3sn.net, and
| | 06:06 | the message itself, "this is from windowOne."
| | 06:08 | So now we're successfully sending
messages from windowTwo to windowOne and then
| | 06:12 | back from windowOne to windowTwo.
| | 06:16 | We'll take a look at a more
interactive example later in the course.
| | Collapse this transcript |
| Handling errors| 00:00 | There are few different types of errors
you'll be concerned with in your HTML5
| | 00:03 | messaging application.
| | 00:05 | Fortunately, most of these
can be handled in the same way.
| | 00:09 | Here we have a working copy of errors-
one start.html and errors-two start.html.
| | 00:13 | I've made working copies on my server,
and I'm editing directly on my server.
| | 00:19 | We'll just take a moment now and page
through these for the benefit of those of
| | 00:22 | you who need that. And here's errors-two.
| | 00:47 | Now the first thing we want to do is we
want to go into each of these files and
| | 00:51 | edit our constants, make
sure those are set correctly.
| | 00:54 | Here we have originTwo, which is set to
the hostname of the server with working
| | 00:59 | two on it, and URL two, which is the
complete URL to errors-two-working.html. And
| | 01:07 | we'll go into errors-two
and check the same thing.
| | 01:11 | And here's the line that you want be
concerned with, and make sure that that has
| | 01:15 | the hostname for your originOne server.
| | 01:20 | And now coming back here into
errors-one, we need to add the event handler
| | 01:26 | for the error function.
| | 01:28 | You notice down here we have a
function called windowErrorHandler, and this is
| | 01:32 | the error handler, actually for both
of these. We have the same function in
| | 01:36 | both of these files.
| | 01:37 | And so that's called windowErrorHandlers.
I'm just going to put that in my copy
| | 01:40 | buffer and come up here into the init
function and add a handler for that.
| | 01:45 | Now in this case I'm going to use
an IDL handler, so I'm going to say
| | 01:50 | window.onerror = and the name
of that function with a semicolon.
| | 01:56 | I am going to save that.
| | 01:58 | The reason I'm using an IDL listener
instead of an addEventListener is that
| | 02:03 | support for error handlers with
addEventListeners is inconsistent amongst
| | 02:07 | the different browsers.
| | 02:09 | And even here on Firefox
it's not completely implemented.
| | 02:13 | So this works well with the IDL
listener and it does not work well with
| | 02:16 | the addEventListener.
| | 02:18 | So I'm just going to make copy of this
line, and I am going to put exactly this
| | 02:21 | same line into errors-two-working.html.
I'll scroll down here to the init function
| | 02:28 | and paste it in right there and press Save.
| | 02:32 | So now we have the event listener
installed for onerror in both of our files, and
| | 02:38 | I am going to come over here
to the browser and load this up.
| | 02:40 | So I'm going to load up error-one-
working.html on my server, and there you see
| | 02:45 | the messages going back and
forth exactly how we expect them to.
| | 02:49 | And now we'll just start introducing
some errors and see how that works.
| | 02:52 | It's a really good idea to play around
with errors when you're building error
| | 02:56 | handlers, so that you know what to expect.
| | 03:00 | So the first thing we'll do is we'll
change our origin from two to three. So
| | 03:05 | this is in errors-one-working.
| | 03:07 | And so when we come in here and handle
message events, the first thing we do is
| | 03:12 | we check if the event origin is equal
to this constant and if not, we display
| | 03:17 | this error message here.
| | 03:18 | I am going to come back over here
into the browser and reload this. And you
| | 03:22 | notice we get the message, "message from
untrusted origin" and it lists the origin
| | 03:27 | where the message came from, which is
different than what it was expecting,
| | 03:30 | because here it's
expecting three instead of two.
| | 03:34 | So this is a message that we're
sending out ourselves from this test, and so
| | 03:38 | it's not really using the onerror handler.
Let's go ahead and use the onerror handler now.
| | 03:44 | So I'm going to change that back, and
I am going to come down here and put
| | 03:48 | something nonsensical in this postMessage.
I'm just going to say foo. That's not a
| | 03:53 | full URL and so if for some
reason you had an error like that,
| | 03:58 | we'll go back into the browser and we'll
bring that error up and you see we have
| | 04:02 | an uncaught exception.
| | 04:04 | So, this is our error handler working.
| | 04:07 | You notice when we come down here to our
ErrorHandler, it prints the message and
| | 04:11 | the file name and the line number.
| | 04:13 | And here we have the uncaught
exception message and the file name and the
| | 04:20 | line number right there.
| | 04:21 | So this gives us some idea of what the
problem is: an invalid or illegal string
| | 04:26 | was specified on line 44. And if we
come back up here to line 44, we
| | 04:32 | can deduce what the problem is. So
I'm just going to put that back to our
| | 04:36 | constant, and let's go make another error.
| | 04:38 | If I come down here to line 54 and I
actually call a function that's not
| | 04:43 | defined--I just misspelled this
function here instead of log its xlog, and so
| | 04:48 | I'll press Save and we'll come back over
here to the browser and we'll load that up.
| | 04:52 | And we see it says xlog is not
defined, and it doesn't run the rest of the
| | 04:56 | script; it just stops right there. xlog
is not defined, gives us the file name and
| | 05:01 | the line number on line 54.
| | 05:03 | So that's exactly what we expect.
| | 05:05 | On the other hand, if we introduce
some error here by misspelling the word
| | 05:09 | function, this will not catch the error.
| | 05:11 | Why? Because this is the function where
the error handler is actually installed.
| | 05:18 | And so if we never get to that line, we're
not going to get our error handler at all.
| | 05:22 | So if I save this and bring this up
and run it, you'll see that I get no
| | 05:26 | error message at all.
| | 05:27 | On the other hand, I can come up here to
Tools > Web Developer. This is in the
| | 05:32 | Firefox browser. You have something
like this in most of the browsers.
| | 05:35 | Now bring up the console and if I
press Reload, you'll notice that I actually
| | 05:41 | get an error message. It's a typical
cascading interpreter error message that
| | 05:46 | doesn't really tell you what the problem is,
but it gives you an idea of where to look.
| | 05:50 | It says it's missing a semicolon
| | 05:51 | around line 51. And in fact what it is,
is it's got an unrecognized keyword. And
| | 05:57 | so we take out that x, and we save it,
and we come back in here, and we reload, and
| | 06:02 | we see that everything runs as we expected to.
| | 06:04 | And I can take down that web developer console.
| | 06:08 | And so now that we have our error
handler working, we have a complete set of
| | 06:11 | tools for HTML5 messaging, and we can
look at a more interactive example in
| | 06:16 | the next chapter.
| | Collapse this transcript |
|
|
3. Cross-Document MessagingAn interactive example| 00:00 | Now let's take a look at a more
interactive example of cross-origin messaging.
| | 00:04 | This is a little chat app, and while
it may not be terribly useful to chat
| | 00:09 | between two windows on a single
desktop, it does give us an opportunity to
| | 00:13 | explore some of the
subtleties of the messaging interface.
| | 00:16 | So this application works much like the
ones that we've seen so far; in fact it
| | 00:20 | uses a lot of the same code.
| | 00:22 | The first thing that it does is it loads
up the second window inside a frame, and
| | 00:27 | then the second window inside a frame
sends a message back to the first window
| | 00:31 | to tell it that it's loaded.
| | 00:33 | So you'll see in the first window, which
is the outer one, we have this log "this
| | 00:37 | is windowOne" and its host, one.3sn.net.
And windowTwo is on two.3sn.net so they
| | 00:44 | are in different origins.
| | 00:46 | And then once windowTwo gets loaded,
it sends this message to windowOne that
| | 00:50 | says, "windowTwo is loaded."
| | 00:52 | And the purpose of that is so that
windowOne now has a handle to windowTwo's
| | 00:58 | window object or rather, a window proxy
object that works just like its window object.
| | 01:02 | You'll also notice that it says info,
and the reason for that is that we're
| | 01:07 | actually sending some structured data that
categorizes the different types of messages.
| | 01:11 | And we have two different types of
messages: we have info message and we
| | 01:14 | have chat messages.
| | 01:15 | So when I come up here and I type a
message, a chat message, you'll see that
| | 01:21 | that message shows up over here
without saying info in front of it.
| | 01:24 | And if I send one over here, you
see that it comes up over here without it
| | 01:31 | saying info in front of it.
| | 01:33 | And the reason for that is that there
are actually two different categories of
| | 01:36 | messages that are being sent, and it's
being sent as structured data with JSON.
| | 01:41 | And the reason we're using JSON is
because this application worked just fine with
| | 01:46 | the structured data except
on the Internet Explorer.
| | 01:49 | And in order to for it to work on
Internet Explorer, we had to use JSON, because
| | 01:53 | Internet Explorer is only
sending strings in its data payload.
| | 01:57 | So now that we've seen how the app works,
in the next movie we'll take a look at
| | 02:01 | the code and see how it's implemented.
| | Collapse this transcript |
| Exploring the example code| 00:00 | So this is our little chat
application, and you can see that I can type in a
| | 00:04 | message here, "hi there," and it comes up
over there. And I can type in a message
| | 00:09 | here and it says, "hi back," and that one
comes up over here. And these are in two
| | 00:15 | different domains, which means that
they're in two different origins for the
| | 00:18 | purposes of the same-origin policy.
| | 00:22 | So let's take a look at how this
works and how this is implemented.
| | 00:24 | Here we have chat-one.html, and this is
the one that's running on one.3sn.net,
| | 00:30 | and here we have chat-two.html,
which is running on two.3sn.net.
| | 00:36 | So before we move forward, let's just
take a quick browse through it for the
| | 00:39 | people that are typing along with us.
| | 00:57 | So that was chat-one.html, and
now we'll look at chat-two.html.
| | 01:19 | And the time-string gets cut off
there just a little bit. There it is. And there we have it.
| | 01:30 | So the first thing you want to do is you
want to come down here in both of these
| | 01:35 | and make sure that your URLs and
origin strings are correct for your server.
| | 01:41 | These are correct for my server here
on 36 and 37 in the chat-one, and in
| | 01:46 | chat-two it's right there on line 24.
| | 01:48 | So you want to make sure that
those are correct for your server.
| | 01:52 | So there are a couple of things that are
different here and that make this work.
| | 01:58 | First of course we have the init
function, which gets called by onload, way
| | 02:03 | down there on line 131.
| | 02:06 | And in chat-one really all its doing is
setting up the event handlers, loading
| | 02:12 | the frame, and selecting the chat text box.
| | 02:17 | And so if we come down here into the
HTML, you notice that we just have this
| | 02:22 | little form with an onSubmit, so
it doesn't have a Submit button.
| | 02:25 | All you do is press Enter on the one
field. And it's got this one text field, and
| | 02:30 | it is called chatText.
| | 02:32 | So up here in the init function you
see it gets that element using the little
| | 02:37 | element shortcut that I've
got down here in my Utilities.
| | 02:40 | It gets that element and it calls select
on it, and that's what gives it, when we
| | 02:45 | load this page up, you notice the
first thing it does is it selects whatever
| | 02:49 | text is in that box and
it puts the cursor there.
| | 02:53 | Other than that, it's just waiting for a
message to come in. And when a message
| | 02:56 | does come in, it calls this
handleMessage event handler, and you'll notice that
| | 03:02 | it calls JSON.parse on the event data.
| | 03:06 | And the reason for this is that
whenever we send a message--notice here is our
| | 03:10 | sendChat function--when we send a
message we call sendObject, and sendObject
| | 03:15 | actually takes that message and it calls
stringify on the JSON, so that it takes
| | 03:20 | that message it, converts it to JSON,
and then it post it as a text string.
| | 03:25 | And the reason for this of course is so
that it will work in Internet Explorer.
| | 03:29 | So that adds a little bit of complexity.
| | 03:30 | chat-two is almost exactly the same.
| | 03:36 | The main difference being in the init.
Because when the init gets called, it can
| | 03:41 | grab that parent object and call it
windowOne, and it calls sendObject again so
| | 03:49 | that it gets JSON-stringified to send
that windowTwo loaded message we saw over
| | 03:54 | here info windowTwo loaded.
| | 03:57 | And so all of the messages are being
sent as structured data. So this message
| | 04:02 | is being sent as an info-type message,
and the chat messages are being sent as
| | 04:07 | chat-type messages.
| | 04:09 | And all of that gets stringified in sendObject.
| | 04:15 | So really, those are the only
significant differences between this and the
| | 04:19 | applications that we've seen earlier,
and so it makes it really simple to send
| | 04:27 | arbitrary data back and forth
between two windows in different origins.
| | 04:35 | So you can see that the HTML5 messaging
API is simple enough that it can get out
| | 04:41 | of your way and allow you to get
creative with your applications.
| | 04:44 | Obviously this is a contrived
application designed to demonstrate the features
| | 04:48 | of the interface, but hopefully you can
see how easy it is to implement cross-
| | 04:52 | origin scripting with the HTML5
messaging API, and now you can use it in your
| | 04:58 | own real-world applications.
| | Collapse this transcript |
|
|
ConclusionGoodbye| 00:00 | In this course my goal was to give
you a good understanding of the HTML5
| | 00:04 | messaging application programming interface.
| | 00:07 | I've covered how the API works, how to
setup the event handlers, how to send and
| | 00:11 | receive data, and how to handle
errors in your messaging applications.
| | 00:15 | Using these features, you should be able
to implement cross-origin scripting for
| | 00:19 | your own applications.
| | 00:21 | As with most of the HTML5 application
technologies, the specifications for the
| | 00:25 | HTML5 messaging API remains in flux.
| | 00:29 | I suggest that you keep up with these
changes in order to make sure that your
| | 00:33 | code works with current and future browsers.
| | 00:36 | And be sure to check out the other
HTML5 titles, as well as the excellent
| | 00:40 | JavaScript Essential Training with
Simon Allardice here on the lynda.com
| | 00:45 | Online Training Library.
| | 00:46 | As always, feel free to use my working
examples as a starting point for your own
| | 00:50 | applications, and I look forward to
seeing what you do with the HTML5 messaging
| | 00:55 | API in your own projects.
| | Collapse this transcript |
|
|