JsonP2.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <title>The source code</title>
  6. <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
  7. <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
  8. <style type="text/css">
  9. .highlight { display: block; background-color: #ddd; }
  10. </style>
  11. <script type="text/javascript">
  12. function highlight() {
  13. document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14. }
  15. </script>
  16. </head>
  17. <body onload="prettyPrint(); highlight();">
  18. <pre class="prettyprint lang-js"><span id='Ext-data-proxy-JsonP'>/**
  19. </span> * @author Ed Spencer
  20. *
  21. * The JsonP proxy is useful when you need to load data from a domain other than the one your application is running on. If
  22. * your application is running on http://domainA.com it cannot use {@link Ext.data.proxy.Ajax Ajax} to load its data
  23. * from http://domainB.com because cross-domain ajax requests are prohibited by the browser.
  24. *
  25. * We can get around this using a JsonP proxy. JsonP proxy injects a `&lt;script&gt;` tag into the DOM whenever an AJAX request
  26. * would usually be made. Let's say we want to load data from http://domainB.com/users - the script tag that would be
  27. * injected might look like this:
  28. *
  29. * &lt;script src=&quot;http://domainB.com/users?callback=someCallback&quot;&gt;&lt;/script&gt;
  30. *
  31. * When we inject the tag above, the browser makes a request to that url and includes the response as if it was any
  32. * other type of JavaScript include. By passing a callback in the url above, we're telling domainB's server that we want
  33. * to be notified when the result comes in and that it should call our callback function with the data it sends back. So
  34. * long as the server formats the response to look like this, everything will work:
  35. *
  36. * someCallback({
  37. * users: [
  38. * {
  39. * id: 1,
  40. * name: &quot;Ed Spencer&quot;,
  41. * email: &quot;ed@sencha.com&quot;
  42. * }
  43. * ]
  44. * });
  45. *
  46. * As soon as the script finishes loading, the 'someCallback' function that we passed in the url is called with the JSON
  47. * object that the server returned.
  48. *
  49. * JsonP proxy takes care of all of this automatically. It formats the url you pass, adding the callback parameter
  50. * automatically. It even creates a temporary callback function, waits for it to be called and then puts the data into
  51. * the Proxy making it look just like you loaded it through a normal {@link Ext.data.proxy.Ajax AjaxProxy}. Here's how
  52. * we might set that up:
  53. *
  54. * Ext.define('User', {
  55. * extend: 'Ext.data.Model',
  56. * fields: ['id', 'name', 'email']
  57. * });
  58. *
  59. * var store = Ext.create('Ext.data.Store', {
  60. * model: 'User',
  61. * proxy: {
  62. * type: 'jsonp',
  63. * url : 'http://domainB.com/users'
  64. * }
  65. * });
  66. *
  67. * store.load();
  68. *
  69. * That's all we need to do - JsonP proxy takes care of the rest. In this case the Proxy will have injected a script tag
  70. * like this:
  71. *
  72. * &lt;script src=&quot;http://domainB.com/users?callback=callback1&quot;&gt;&lt;/script&gt;
  73. *
  74. * # Customization
  75. *
  76. * This script tag can be customized using the {@link #callbackKey} configuration. For example:
  77. *
  78. * var store = Ext.create('Ext.data.Store', {
  79. * model: 'User',
  80. * proxy: {
  81. * type: 'jsonp',
  82. * url : 'http://domainB.com/users',
  83. * callbackKey: 'theCallbackFunction'
  84. * }
  85. * });
  86. *
  87. * store.load();
  88. *
  89. * Would inject a script tag like this:
  90. *
  91. * &lt;script src=&quot;http://domainB.com/users?theCallbackFunction=callback1&quot;&gt;&lt;/script&gt;
  92. *
  93. * # Implementing on the server side
  94. *
  95. * The remote server side needs to be configured to return data in this format. Here are suggestions for how you might
  96. * achieve this using Java, PHP and ASP.net:
  97. *
  98. * Java:
  99. *
  100. * boolean jsonP = false;
  101. * String cb = request.getParameter(&quot;callback&quot;);
  102. * if (cb != null) {
  103. * jsonP = true;
  104. * response.setContentType(&quot;text/javascript&quot;);
  105. * } else {
  106. * response.setContentType(&quot;application/x-json&quot;);
  107. * }
  108. * Writer out = response.getWriter();
  109. * if (jsonP) {
  110. * out.write(cb + &quot;(&quot;);
  111. * }
  112. * out.print(dataBlock.toJsonString());
  113. * if (jsonP) {
  114. * out.write(&quot;);&quot;);
  115. * }
  116. *
  117. * PHP:
  118. *
  119. * $callback = $_REQUEST['callback'];
  120. *
  121. * // Create the output object.
  122. * $output = array('a' =&gt; 'Apple', 'b' =&gt; 'Banana');
  123. *
  124. * //start output
  125. * if ($callback) {
  126. * header('Content-Type: text/javascript');
  127. * echo $callback . '(' . json_encode($output) . ');';
  128. * } else {
  129. * header('Content-Type: application/x-json');
  130. * echo json_encode($output);
  131. * }
  132. *
  133. * ASP.net:
  134. *
  135. * String jsonString = &quot;{success: true}&quot;;
  136. * String cb = Request.Params.Get(&quot;callback&quot;);
  137. * String responseString = &quot;&quot;;
  138. * if (!String.IsNullOrEmpty(cb)) {
  139. * responseString = cb + &quot;(&quot; + jsonString + &quot;)&quot;;
  140. * } else {
  141. * responseString = jsonString;
  142. * }
  143. * Response.Write(responseString);
  144. */
  145. Ext.define('Ext.data.proxy.JsonP', {
  146. extend: 'Ext.data.proxy.Server',
  147. alternateClassName: 'Ext.data.ScriptTagProxy',
  148. alias: ['proxy.jsonp', 'proxy.scripttag'],
  149. requires: ['Ext.data.JsonP'],
  150. defaultWriterType: 'base',
  151. <span id='Ext-data-proxy-JsonP-cfg-callbackKey'> /**
  152. </span> * @cfg {String} callbackKey
  153. * See {@link Ext.data.JsonP#callbackKey}.
  154. */
  155. callbackKey : 'callback',
  156. <span id='Ext-data-proxy-JsonP-cfg-recordParam'> /**
  157. </span> * @cfg {String} recordParam
  158. * The param name to use when passing records to the server (e.g. 'records=someEncodedRecordString'). Defaults to
  159. * 'records'
  160. */
  161. recordParam: 'records',
  162. <span id='Ext-data-proxy-JsonP-cfg-autoAppendParams'> /**
  163. </span> * @cfg {Boolean} autoAppendParams
  164. * True to automatically append the request's params to the generated url. Defaults to true
  165. */
  166. autoAppendParams: true,
  167. constructor: function(){
  168. this.addEvents(
  169. <span id='Ext-data-proxy-JsonP-event-exception'> /**
  170. </span> * @event
  171. * Fires when the server returns an exception
  172. * @param {Ext.data.proxy.Proxy} this
  173. * @param {Ext.data.Request} request The request that was sent
  174. * @param {Ext.data.Operation} operation The operation that triggered the request
  175. */
  176. 'exception'
  177. );
  178. this.callParent(arguments);
  179. },
  180. <span id='Ext-data-proxy-JsonP-method-doRequest'> /**
  181. </span> * @private
  182. * Performs the read request to the remote domain. JsonP proxy does not actually create an Ajax request,
  183. * instead we write out a `&lt;script&gt;` tag based on the configuration of the internal Ext.data.Request object
  184. * @param {Ext.data.Operation} operation The {@link Ext.data.Operation Operation} object to execute
  185. * @param {Function} callback A callback function to execute when the Operation has been completed
  186. * @param {Object} scope The scope to execute the callback in
  187. */
  188. doRequest: function(operation, callback, scope) {
  189. //generate the unique IDs for this request
  190. var me = this,
  191. writer = me.getWriter(),
  192. request = me.buildRequest(operation),
  193. params = request.params;
  194. if (operation.allowWrite()) {
  195. request = writer.write(request);
  196. }
  197. // apply JsonP proxy-specific attributes to the Request
  198. Ext.apply(request, {
  199. callbackKey: me.callbackKey,
  200. timeout: me.timeout,
  201. scope: me,
  202. disableCaching: false, // handled by the proxy
  203. callback: me.createRequestCallback(request, operation, callback, scope)
  204. });
  205. // prevent doubling up
  206. if (me.autoAppendParams) {
  207. request.params = {};
  208. }
  209. request.jsonp = Ext.data.JsonP.request(request);
  210. // restore on the request
  211. request.params = params;
  212. operation.setStarted();
  213. me.lastRequest = request;
  214. return request;
  215. },
  216. <span id='Ext-data-proxy-JsonP-method-createRequestCallback'> /**
  217. </span> * @private
  218. * Creates and returns the function that is called when the request has completed. The returned function
  219. * should accept a Response object, which contains the response to be read by the configured Reader.
  220. * The third argument is the callback that should be called after the request has been completed and the Reader has decoded
  221. * the response. This callback will typically be the callback passed by a store, e.g. in proxy.read(operation, theCallback, scope)
  222. * theCallback refers to the callback argument received by this function.
  223. * See {@link #doRequest} for details.
  224. * @param {Ext.data.Request} request The Request object
  225. * @param {Ext.data.Operation} operation The Operation being executed
  226. * @param {Function} callback The callback function to be called when the request completes. This is usually the callback
  227. * passed to doRequest
  228. * @param {Object} scope The scope in which to execute the callback function
  229. * @return {Function} The callback function
  230. */
  231. createRequestCallback: function(request, operation, callback, scope) {
  232. var me = this;
  233. return function(success, response, errorType) {
  234. delete me.lastRequest;
  235. me.processResponse(success, operation, request, response, callback, scope);
  236. };
  237. },
  238. // inherit docs
  239. setException: function(operation, response) {
  240. operation.setException(operation.request.jsonp.errorType);
  241. },
  242. <span id='Ext-data-proxy-JsonP-method-buildUrl'> /**
  243. </span> * Generates a url based on a given Ext.data.Request object. Adds the params and callback function name to the url
  244. * @param {Ext.data.Request} request The request object
  245. * @return {String} The url
  246. */
  247. buildUrl: function(request) {
  248. var me = this,
  249. url = me.callParent(arguments),
  250. params = Ext.apply({}, request.params),
  251. filters = params.filters,
  252. records,
  253. filter, i;
  254. delete params.filters;
  255. if (me.autoAppendParams) {
  256. url = Ext.urlAppend(url, Ext.Object.toQueryString(params));
  257. }
  258. if (filters &amp;&amp; filters.length) {
  259. for (i = 0; i &lt; filters.length; i++) {
  260. filter = filters[i];
  261. if (filter.value) {
  262. url = Ext.urlAppend(url, filter.property + &quot;=&quot; + filter.value);
  263. }
  264. }
  265. }
  266. //if there are any records present, append them to the url also
  267. records = request.records;
  268. if (Ext.isArray(records) &amp;&amp; records.length &gt; 0) {
  269. url = Ext.urlAppend(url, Ext.String.format(&quot;{0}={1}&quot;, me.recordParam, me.encodeRecords(records)));
  270. }
  271. return url;
  272. },
  273. //inherit docs
  274. destroy: function() {
  275. this.abort();
  276. this.callParent(arguments);
  277. },
  278. <span id='Ext-data-proxy-JsonP-method-abort'> /**
  279. </span> * Aborts the current server request if one is currently running
  280. */
  281. abort: function() {
  282. var lastRequest = this.lastRequest;
  283. if (lastRequest) {
  284. Ext.data.JsonP.abort(lastRequest.jsonp);
  285. }
  286. },
  287. <span id='Ext-data-proxy-JsonP-method-encodeRecords'> /**
  288. </span> * Encodes an array of records into a string suitable to be appended to the script src url. This is broken out into
  289. * its own function so that it can be easily overridden.
  290. * @param {Ext.data.Model[]} records The records array
  291. * @return {String} The encoded records string
  292. */
  293. encodeRecords: function(records) {
  294. var encoded = &quot;&quot;,
  295. i = 0,
  296. len = records.length;
  297. for (; i &lt; len; i++) {
  298. encoded += Ext.Object.toQueryString(records[i].getData());
  299. }
  300. return encoded;
  301. }
  302. });
  303. </pre>
  304. </body>
  305. </html>