我正在尝试为我们在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不应违反同一原产地政策。这是一个错误吗?有解决方法吗?
答案 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;
}
?>