书签中的XmlHttpRequest在GET上返回空的responseText?

时间:2010-04-26 17:46:06

标签: javascript xmlhttprequest bookmarklet

我正在尝试为我们在http://esv.to建立的特殊网址缩短服务构建一个javascript bookmarklet,用于缩短经文引用(即“Matthew 5”变为“http://esv.to/Mt5”。书签是应该向http://api.esv.to/Matthew+5发送GET请求,该请求会返回text/plain的{​​{1}}响应。

bookmarklet本身的代码如下所示(为了便于阅读而扩展):

http://esv.to/Mt5

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); 的代码如下所示:

http://esv.to/media/js/bookmarklet.js

http://esv.to本身调用时,书签正常工作。但是当在另一个页面上使用时,它不会。奇怪的是,当我观察来自Firebug的请求时,响应为(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(); })(); ,浏览器下载17个字节(返回字符串的长度),但响应正文为空!不会抛出任何错误,只是XmlHttpRequest对象上的空responseText。

现在,根据Ajax call from Bookmarklet,GET不应违反同一原产地政策。这是一个错误吗?有解决方法吗?

1 个答案:

答案 0 :(得分:8)

跨站点XMLHttpRequests只能在实现W3C Cross-Origin Resource Sharing规范的浏览器中完成,并且服务器返回相应的访问控制头(请参阅MDC article),例如:

Access-Control-Allow-Origin: *

但并非所有浏览器都实现此功能。进行跨站点请求的唯一可靠方法是使用JSONP,用于(未经测试)示例:

(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);
    });
})();

当服务器看到callback参数时,它将需要返回text/javascript而不是text/plain,并且响应正文需要包含在所提供的回调的调用中,例如:

<?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;
}
?>