XmlHttpRequest in bookmark returns empty Text response to GET?

I am trying to create a javascript bookmarklet for a special URL shortening service that we built on http://esv.to to shorten scripture references (i.e., "Matthew 5" becomes " http://esv.to/Mt5 . Estimated the booklet should execute a GET request for http://api.esv.to/Matthew+5 , which returns a text/plain response http://esv.to/Mt5 .

The code of the bookmarklet itself is as follows (extended for readability):

 var body = document.getElementsByTagName('body')[0], script = document.createElement('script'); script.type = 'text/javascript'; script.src = 'http://esv.to/media/js/bookmarklet.js'; body.appendChild(script); void(0); 

The code from http://esv.to/media/js/bookmarklet.js as follows:

 (function() { function shorten(ref, callback) { var url = "http://esv.to/api/" + escape(ref); var req = new XMLHttpRequest(); req.onreadystatechange = function shortenIt() { if ( this.readyState == 4 && this.status == 200 ) { callback(req.responseText); }; }; req.open( "GET", url ); req.send(); }; function doBookmarklet() { var ref = prompt("Enter a scripture reference or keyword search to link to:", "") shorten(ref, function (short) { prompt("Here is your shortened ESV URL:", short); }); }; doBookmarklet(); })(); 

When called from http://esv.to , the bookmarks itself works correctly. But when used on another page, this is not so. The strange thing is, when I look at a request from Firebug, the response is 200 OK , the browser loads 17 bytes (the length of the returned string), but the response body is empty! The error does not occur, but the empty responseText object of the XmlHttpRequest object.

Now, according to the Ajax call from Bookmarklet , the GET should not violate the same origin policy. This is mistake? Is there a workaround?

+4
source share
1 answer

Cross-site XMLHttpRequests can only be run in browsers that implement the W3C Cross-Origin Resource Sharing specification, and if the server returns the appropriate access (see the MDC article ), for example:

Access-Control-Allow-Origin: *

But this is not implemented by all browsers. The only reliable way to execute cross-site request requests is to use JSONP as an example (untested):

 (function() { function shorten(ref, callback){ var callbackFuncName = 'esvapiJSONPCallback' + (new Date()).valueOf(); var script = document.createElement('script'); script.type = "text/javascript"; script.src = "http://esv.to/api/" + escape(ref) + "?callback=" + callbackFuncName; window[callbackFuncName] = function(shorturl){ script.parentNode.removeChild(script); window.callbackFuncName = null; delete window[callbackFuncName]; callback(shorturl); }; document.getElementsByTagName("head")[0].appendChild(script); } var ref = prompt("Enter a scripture reference or keyword search to link to:", ""); shorten(ref, function(shorturl) { prompt("Here is your shortened ESV URL:", shorturl); }); })(); 

When the server sees the callback parameter, then it will need to return text/javascript instead of text/plain , and the response body will need to be wrapped with a call to the provided callback, for example:

 <?php #... after $shorturl is set ... if(isset($_GET['callback'])){ header('Content-Type: text/javascript'); $callback = preg_replace('/\W+/', '', $_GET['callback']); #sanitize print $callback . "(" . json_encode($shorturl) . ");"; } else { header("Content-Type: text/plain"); print $shorturl; } ?> 
+8
source

Source: https://habr.com/ru/post/1308051/


All Articles