Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 233 lines (165 sloc) 9.256 kB
e08bbf3 @pyronicide Quick 'what in the world is this' section
authored
1 # What is this?
2
3 janky.post is a javascript library that simplifies cross-domain
4 request/response communication using regular GET/POST for the request and an
5 easy to implement response format.
6
f77aa79 @pyronicide Creating docs
authored
7 # Why, for goodness sakes, why?!?
8
9 By default, javascript keeps you pretty tied down security wise. You can only
10 send XHR requests to the same domain. And, of course, the port is part of what
11 is thought of as the "domain" (eg. http://example.com:80 is a separate domain
12 from http://example.com:8080). With the advent of services everywhere, it has
13 become more and more important to be able to pass data from one domain to
14 another. Not only do you not want to see that data but it doesn't make sense to
15 have an extra request hitting your server just to proxy it on back to the
16 service that you're using.
17
18 There are many different ways to do cross-domain communication in javascript
19 but they all have tradeoffs unfortunately:
20
21 - JSONP - This adds `<script src="http://example.com/remote?callback=foo"></script>` to your web
22 page. When the server receives this, it will write you back a script along
23 the lines of `foo({ data: "my response" })`. On the plus side, this is pretty
24 easy from both the client (there's great support in jquery) and the
25 server. Unfortunately, you don't get any real information on errors that
26 occur to the request and you're limited to GET requests. Since GET requests
27 are limited to about 2k, this ends up being very limiting for any large
28 requests.
29
30 - Access-Control - Modern browsers add an Access-Control header to XHR
31 requests. If the server responds in kind, your request is allowed
32 through. Just like JSONP, this is really easy on the client
33 side. Unfortunately, IE6/7 are completely unsupported and IE8 needs a bunch
34 of special treatment that isn't implemented in common libraries. It also
fc3bde7 @pyronicide Working on the docs
authored
35 requires some header hackery that isn't the easiest thing in the
36 world. Finally, these requests are actually 2 requests in sequence (one to
37 get the Access-Control restrictions, the second to actually send the
38 request). This just adds latency to your users that they don't need.
f77aa79 @pyronicide Creating docs
authored
39
40 - Flash/Silverlight - These are probably the easiest of all
41 (unfortunately). You can just put a crossdomain.xml file at the remote
42 server's root and you're good to go. The obvious drawbacks however, are that
43 you now are requiring the use of flash or sliverlight for simple
44 client/server communication.
45
fc3bde7 @pyronicide Working on the docs
authored
46 janky.post tries to fix some of these drawbacks. Here's a quick example of
47 doing a cross domain request from your local page:
48
49 janky({ url: "http://example.com:8080/api",
50 data: { foo: 'bar', baz: [1,2,3] },
51 success: function(resp) {
52 console.log('server responded with: ' + resp);
53 },
54 error: function() {
55 console.log('error =(');
56 }
57 });
58
59 That example basically replicates a JSONP result (but you'll notice that
60 there's actually errors that occur, no firing requests into the ether). The
61 other cool feature that janky.post gets you is the ability to do POST along
62 with GET. Just add `method: "post"` to your janky options and you're set.
63
b7b5d24 @pyronicide Adding demo server stuff to the readme
authored
64 # Demo!
65
66 Take some time to play around with [the
67 demo](http://saunter.org/janky.post/demo). It should give you a good idea of
68 what you can do with janky.post.
69
fc3bde7 @pyronicide Working on the docs
authored
70 # Getting setup
71
edcc907 @pyronicide Tweaking the docs
authored
72 On the client side, there's only one dependency for janky.post: json2.js (for
73 IE support). You've probably already have json2.js added somewhere on the page
74 but if you don't, you can get it from [the
75 source](http://json.org/json2.js). Then, just add janky.post to the script
76 blocks of your page and you're ready to go. (Take a look in the lib directory
77 for both the minified and the verbose versions).
fc3bde7 @pyronicide Working on the docs
authored
78
e5b9499 @pyronicide Update the link
authored
79 <script src="http://saunter.org/janky.post/scripts/json2.js"></script>
061fde7 @pyronicide Using the github pages link
authored
80 <script src="http://saunter.org/janky.post/lib/janky.post.min.js"></script>
fc3bde7 @pyronicide Working on the docs
authored
81
fe36c3d @pyronicide Updates to mention postMessage
authored
82 Note that if you're supporting IE6/7, make sure you also add an empty, static
73d94be @pyronicide formatting
authored
83 page at `http://local_server/janky.html`.
fe36c3d @pyronicide Updates to mention postMessage
authored
84
b7b5d24 @pyronicide Adding demo server stuff to the readme
authored
85 ## Demo server
86
87 To aid in testing the client side of this, once you've added the two scripts
88 above to your pages, try using the demo server to see if everything's working
89 right. To use the demo server, you do something like the following:
90
91 janky({ url: "http://api.jankypost.com/api",
92 data: { ninja: false, robot: true },
93 success: function(resp) { console.log(resp) }
94 });
95
ffe79e1 @pyronicide Adding in api explanation
authored
96 # Using janky.post
97
98 There's only one function call - `janky(settings)`. The settings are:
99
100 - url - Location to send the request to
101
102 - data - An object containing key/value pairs to send to the server. The values
103 can be anything that is JSON serializable.
104
105 - method - The method to use. For now, this is either GET or POST.
106
107 - success - Function to call with the response's result. This is called with
108 the JSON parsed results of the respons from the remote server.
109
110 - error - If any errors occur once the request has been issued, this will be
111 called. At the moment, there are no arguments to this.
112
113 ## Example
114
115 janky({ url: "http://example.com:8080/foo/bar",
116 data: { style: 'foo', ninja: true },
117 method: "post",
118 success: function(resp) {
119 console.log('server response: ' + resp);
120 },
121 error: function() {
122 console.log('there was an error');
123 }
124 });
125
ebd82f3 @pyronicide Implementation instructions for other servers
authored
126 # Server side support
127
128 The list of server side support currently includes:
129
91ee4c6 @pyronicide Fixing a link
authored
130 - [Tornado](https://github.com/pyronicide/janky.post/tree/master/python)
b22b3a5 @pyronicide Fixing up the readmes a little bit
authored
131 - [Google App Engine](https://github.com/pyronicide/janky.post/tree/master/python)
132
ebd82f3 @pyronicide Implementation instructions for other servers
authored
133
134 Please tell me if you implement the server side support for any framework so
135 that I can add it to the list.
136
137 ## Implementing server side support in your own framework
138
139 I'd suggest taking a look at how this whole thing works first. But, if you'd
140 like to skip to the instant howto ....
141
142 As a response, instead of sending back the normal response, you need to send
143 back:
144
145 <html>
146 <head></head>
147 <body>
148 <script type="text/javascript">
149 window.name = "json serialized string containing the response";
fe36c3d @pyronicide Updates to mention postMessage
authored
150 window.parent.postMessage ? window.parent.postMessage(window.name, "*") :
151 location.href = "_origin domain from request + /janky.html";
ebd82f3 @pyronicide Implementation instructions for other servers
authored
152 </script>
153 </body>
154 </html>
155
156 A couple gotchas:
157
158 - The content-type needs to be `text/html`. If you try to do
159 `application/json`, bad things happen.
160
161 - Make sure that your response has been serialized via. JSON as the client
162 library will be expecting that.
163
164 - There is an `_origin` parameter added to every request. Take the root domain
fe36c3d @pyronicide Updates to mention postMessage
authored
165 of that and then add `/janky.html`. For example, if
ebd82f3 @pyronicide Implementation instructions for other servers
authored
166 `_origin=http://example.com:8080/foo/bar.html`, you would set `location.href`
fe36c3d @pyronicide Updates to mention postMessage
authored
167 to `http://example.com:8080/janky.html`. It is important that this gets set
168 this way (so that IE6/7 have a page to redirect back to for the iframe).
7a26690 @pyronicide Adding an explaination of how it all works
authored
169
170 # How it all works
171
172 1. The browser creates a hidden iframe with an empty source (still on the local
173 domain).
edcc907 @pyronicide Tweaking the docs
authored
174
7a26690 @pyronicide Adding an explaination of how it all works
authored
175 5. An `onload` event is attached to the iframe
edcc907 @pyronicide Tweaking the docs
authored
176
7a26690 @pyronicide Adding an explaination of how it all works
authored
177 2. A form is added to the body of that iframe.
edcc907 @pyronicide Tweaking the docs
authored
178
7a26690 @pyronicide Adding an explaination of how it all works
authored
179 3. The `action` parameter of the form is set to the remote server.
edcc907 @pyronicide Tweaking the docs
authored
180
7a26690 @pyronicide Adding an explaination of how it all works
authored
181 4. For each k/v pair in `data` a hidden input is created inside this form.
edcc907 @pyronicide Tweaking the docs
authored
182
183 6. The form is submitted (now on the remote domain).
184
7a26690 @pyronicide Adding an explaination of how it all works
authored
185 7. At this point, the iframe's location.href is on the remote server. This
186 makes it so that the browser can't get at any data but the remote server's
187 page can do anything it wants to the iframe's window.
edcc907 @pyronicide Tweaking the docs
authored
188
fe36c3d @pyronicide Updates to mention postMessage
authored
189 8. The remove server creates a web page that calls window.parent.postMessage().
190
191 9. The `message` (or `onmessage`) event in the parent frame (local server)
192 fires and your `success` method is called.
edcc907 @pyronicide Tweaking the docs
authored
193
fe36c3d @pyronicide Updates to mention postMessage
authored
194 For some discussion on postMessage, take a look at
195 [MDC](https://developer.mozilla.org/En/DOM/Window.postMessage).
7a26690 @pyronicide Adding an explaination of how it all works
authored
196
fe36c3d @pyronicide Updates to mention postMessage
authored
197 Note that for IE6 and 7 there's a different method used. Instead of using
198 postMessage, `window.name` is used. This means that the request goes to the
199 remote server which then redirects back to the local server. The reason that
200 this works has to do with how `window.name` is implemented. At a high level,
201 `window.name` is not reset when a page changes, so when the page has been
202 redirected back to the local domain, the full response can be fetched. There
203 are limits on the response size using this method but the limits are somwhere
204 in the 10mb range. Note that the only limits placed on requests themselves are
205 the normal form limitations.
ad58002 @crdeutsch Updated Readme with info on getting remote server cookies to work in IE
crdeutsch authored
206
207 # Gotchas
208
209 Internet Explorer blocks cookies from iframes, so if you're setting cookies
210 on the remote server you must add a P3P header for IE to accept the cookie.
211
212 More info: http://adamyoung.net/IE-Blocking-iFrame-Cookies
213
214 ## PHP:
215
216 header('P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"');
217
218
219 ## ASP.NET:
220
221 HttpContext.Current.Response.AddHeader("p3p","CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"");
222
223
224 ## Django:
225
226 response = render_to_response('mytemplate.html')
227 response["P3P"] = 'CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"'
228
229
230 ## JSP:
231
232 response.addHeader("P3P","CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"")
Something went wrong with that request. Please try again.