2010-04-26 150 views
4

我正在尝试为缩短圣经引用(即“马太福音5”变成“http://esv.to/Mt5”)的http://esv.to建立一个特殊的网址缩短服务的javascript书签。书签本应该向http://api.esv.to/Matthew+5发出GET请求,返回的一个http://esv.to/Mt5响应text/plain书签小程序中的XmlHttpRequest在GET上返回空的responseText?

(扩大了可读性)为书签本身看起来像这样的代码:

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的代码看起来是这样的:

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

})(); 

当从http://esv.to本身调用时,书签工作正常。但是在另一个页面上使用时,它不会。奇怪的是,当我看到Firebug的请求时,响应是200 OK,浏览器下载了17个字节(返回字符串的长度),但响应正文是空的!没有错误发生,只是XmlHttpRequest对象上的空的responseText。

现在,根据Ajax call from Bookmarklet,GET不应该违反相同的原始策略。这是一个错误?有没有解决方法?

+0

那么回答声称GET不受同源策略约束是不正确的。不知道为什么它成了upvoted。 – 2010-04-28 18:12:01

+0

你有没有试过POST? – 2010-04-28 18:58:24

回答

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

除了少数几个语法错误之外,这些工作相当好!我必须等一天才能接受这个答案,给别人一个机会。谢谢! – 2010-04-28 21:32:43

+0

对不起,语法错误;我认为我纠正了它们。我没有真正运行代码,除了我的MVM(心理虚拟机)。 – 2010-04-28 21:36:17

相关问题