2010-04-26 1 views
4

Я пытаюсь создать букмарклет javascript для специальной службы сокращения URL-адресов, которую мы построили в http://esv.to, для сокращения ссылок на Священные Писания (т. Е. «Matthew 5» становится «http://esv.to/Mt5». Предполагаемый буклет должен делать запрос GET на http://api.esv.to/Matthew+5, который возвращает text/plain ответа http://esv.to/Mt5XmlHttpRequest в букмарклет возвращает пустой ответText на GET?

код для букмарклета сами выглядит следующим образом (расширяется для удобства чтения):.

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 байтов (длина возвращаемой строки), но тело ответа пуст! Ошибка не возникает, а пустой объект responseText объекта XmlHttpRequest.

Теперь, согласно Ajax call from Bookmarklet, GET не должен нарушать одну и ту же политику происхождения. Это ошибка? Есть ли обходной путь?

+0

Этот ответ SO, на который претензии GET не ограничивается одной и той же политикой происхождения, неверен. Не уверен, почему это было поддержано. –

+0

Вы пробовали ПОСТ? –

ответ

8

запросы XMLHttpRequest Cross-сайт может быть сделано только в браузерах, которые реализуют 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

Помимо нескольких синтаксических ошибок, это работает очень хорошо! Я должен подождать один день, прежде чем принять это как ответ, чтобы дать другим шанс. Благодаря! –

+0

Извините за синтаксические ошибки; Думаю, я их исправил. Я действительно не запускал код, кроме моего MVM (интеллектуальная виртуальная машина). –