Загрузка междоменной конечной точки с помощью AJAX


131

Я пытаюсь загрузить междоменную HTML-страницу с помощью AJAX, но, если dataType не равен «jsonp», я не могу получить ответ. Однако при использовании jsonp браузер ожидает MIME-тип скрипта, но получает «text / html».

Мой код для запроса:

$.ajax({
    type: "GET",
    url: "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P@ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute",
    dataType: "jsonp",
}).success( function( data ) {
    $( 'div.ajax-field' ).html( data );
});

Есть ли способ избежать использования jsonp для запроса? Я уже пробовал использовать параметр crossDomain, но это не сработало.

Если нет способа получить HTML-контент в jsonp? В настоящее время консоль сообщает "неожиданный <" в ответе jsonp.


Я решил проблему, создав proxy.php, как описано здесь scode7.blogspot.com/2019/11/…
CodeDezk

Ответы:


235

jQuery Ajax Notes

  • Из-за ограничений безопасности браузера большинство запросов Ajax подчиняются одной и той же политике происхождения ; запрос не может успешно получить данные из другого домена, субдомена, порта или протокола.
  • На запросы сценариев и JSONP не распространяются одинаковые ограничения политики происхождения.

Есть несколько способов преодолеть междоменный барьер:

Есть несколько плагинов, которые помогают с междоменными запросами:

Берегись!

Лучший способ решить эту проблему - создать собственный прокси-сервер в серверной части, чтобы ваш прокси-сервер указывал на службы в других доменах, поскольку в серверной части не существует такого же ограничения политики происхождения . Но если вы не можете этого сделать в бэк-энде, обратите внимание на следующие советы.


Предупреждение!

Использование сторонних прокси-серверов не является безопасной практикой, поскольку они могут отслеживать ваши данные, поэтому их можно использовать с общедоступной информацией, но никогда с личными данными.


В приведенных ниже примерах кода используются jQuery.get () и jQuery.getJSON () , оба являются сокращенными методами jQuery.ajax ().


CORS везде

CORS Anywhere - это прокси-сервер node.js, который добавляет заголовки CORS к проксируемому запросу.
Чтобы использовать API, просто добавьте URL к URL API. (Поддерживает https : см. Репозиторий github )

Если вы хотите автоматически включить междоменные запросы при необходимости, используйте следующий фрагмент:

$.ajaxPrefilter( function (options) {
  if (options.crossDomain && jQuery.support.cors) {
    var http = (window.location.protocol === 'http:' ? 'http:' : 'https:');
    options.url = http + '//cors-anywhere.herokuapp.com/' + options.url;
    //options.url = "http://cors.corsproxy.io/url=" + options.url;
  }
});

$.get(
    'http://en.wikipedia.org/wiki/Cross-origin_resource_sharing',
    function (response) {
        console.log("> ", response);
        $("#viewer").html(response);
});


Независимо от происхождения

Каким бы ни был Origin , это междоменный доступ jsonp . Это альтернатива anyorigin.com с открытым исходным кодом .

Чтобы получить данные с google.com, вы можете использовать этот фрагмент:

// It is good specify the charset you expect.
// You can use the charset you want instead of utf-8.
// See details for scriptCharset and contentType options: 
// http://api.jquery.com/jQuery.ajax/#jQuery-ajax-settings
$.ajaxSetup({
    scriptCharset: "utf-8", //or "ISO-8859-1"
    contentType: "application/json; charset=utf-8"
});

$.getJSON('http://whateverorigin.org/get?url=' + 
    encodeURIComponent('http://google.com') + '&callback=?',
    function (data) {
        console.log("> ", data);

        //If the expected response is text/plain
        $("#viewer").html(data.contents);

        //If the expected response is JSON
        //var response = $.parseJSON(data.contents);
});


Прокси-сервер CORS

Прокси- сервер CORS - это простой прокси-сервер node.js для включения запросов CORS для любого веб-сайта. Это позволяет коду javascript на вашем сайте получать доступ к ресурсам в других доменах, которые обычно блокируются из-за политики того же происхождения.

Как это работает? Прокси-сервер CORS использует совместное использование ресурсов между источниками, которое является функцией, которая была добавлена ​​вместе с HTML 5. Серверы могут указать, что они хотят, чтобы браузеры разрешали другим веб-сайтам запрашивать ресурсы, которые они размещают. CORS Proxy - это просто HTTP-прокси, который добавляет заголовок к ответам, в котором говорится, что «любой может запросить это».

Это еще один способ достичь цели (см. Www.corsproxy.com ). Все, что вам нужно сделать, это удалить http: // и www. из проксируемого URL-адреса и добавьте к URL-адресуwww.corsproxy.com/

$.get(
    'http://www.corsproxy.com/' +
    'en.wikipedia.org/wiki/Cross-origin_resource_sharing',
    function (response) {
        console.log("> ", response);
        $("#viewer").html(response);
});


Прокси-браузер CORS

Недавно я нашел этот, он включает в себя различные утилиты Cross Origin Remote Sharing, ориентированные на безопасность. Но это черный ящик с Flash в качестве бэкэнда.

Вы можете увидеть это в действии здесь: Прокси-браузер CORS
Получите исходный код на GitHub: koto / cors-proxy-browser


4
Вы также можете развернуть свою собственную версию WhateverOrigin.org (или перенести код для собственного использования) отсюда: github.com/ripper234/Whatever-Origin
EpicVoyage

1
На изображения, CSS и внешний javascript можно ссылаться из другого источника, таким образом, в ответе вы можете перейти по строке HTML и заменить src внешних ресурсов
jherax

1
привет, jherax, я использовал Anyorigin, чтобы получить html-страницу (у меня работал только один способ, использовал yql, google и т. д.), но неанглийские символы странные. попробовал закодировать data.contents но не помогло
user217648 09

1
Привет @Miru, как гласит заголовок: «Загрузка междоменной html-страницы с помощью jQuery AJAX», я ответил на заголовок, предоставив несколько примеров использования прокси для выполнения междоменных запросов. Кроме того, в ответ на формулировку вопроса я предоставил несколько ссылок для выполнения междоменных запросов с использованием JSONP с YQL. Приглашаю вас прочитать ссылки, они очень полезные.
jherax

1
Закончил использование метода CORS Anywhere с, $.ajaxPrefilterи он отлично работал. Большое спасибо!
Джошуа Пинтер

24

Вы можете использовать Ajax-cross-origin как плагин jQuery. С помощью этого плагина вы используете jQuery.ajax()кросс-домен. Для этого используются сервисы Google:

Плагин AJAX Cross Origin использует скрипт Google Apps в качестве прокси-получателя jSON, где jSONP не реализован. Когда вы устанавливаете для параметра crossOrigin значение true, плагин заменяет исходный URL-адрес на адрес скрипта Google Apps и отправляет его как закодированный параметр URL-адреса. Скрипт Google Apps использует ресурсы серверов Google для получения удаленных данных и возврата их клиенту как JSONP.

Использовать очень просто:

    $.ajax({
        crossOrigin: true,
        url: url,
        success: function(data) {
            console.log(data);
        }
    });

Вы можете прочитать здесь: http://www.ajax-cross-origin.com/


22
Насколько я понимаю, этот плагин никогда не работал. Он ничего не делает в Chrome.
Майкл

Как я могу пройти аутентификацию на сервере?
sttaq

прекрасно работает! Используемый мной API не поддерживает ни JSONP, ни CORS, поэтому это единственное, что сработало. Большое спасибо!
JP Lew

crossOriginОпция jQuery, конечно же, ничего не делает для смягчения политики одинакового происхождения. Я бы удалил этот ответ, если бы мог
Фил

13

Если внешний сайт не поддерживает JSONP или CORS, единственный вариант - использовать прокси.

Создайте сценарий на своем сервере, который запрашивает этот контент, а затем используйте jQuery ajax, чтобы запустить сценарий на вашем сервере.


5

Просто поместите это в заголовок своей страницы PHP, и он не будет работать без API:

header('Access-Control-Allow-Origin: *'); //allow everybody  

или

header('Access-Control-Allow-Origin: http://codesheet.org'); //allow just one domain 

или

$http_origin = $_SERVER['HTTP_ORIGIN'];  //allow multiple domains

$allowed_domains = array(
  'http://codesheet.org',
  'http://stackoverflow.com'
);

if (in_array($http_origin, $allowed_domains))
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

Мне интересно откуда $_SERVER['HTTP_ORIGIN']взялось. Я не нашел его ни в документации по PHP, ни где-либо еще.
Zsolti

Хм, кажется, он заполняется только запросами AJAX. Во всяком случае, спасибо за ответ.
Zsolti

0

Я публикую это на случай, если кто-то столкнется с той же проблемой, с которой я столкнулся прямо сейчас. У меня есть термопринтер Zebra, оснащенный сервером печати ZebraNet, который предлагает пользовательский интерфейс на основе HTML для редактирования нескольких параметров, просмотра текущего состояния принтера и т. Д. Мне нужно получить статус принтера, который отображается на одной из этих html-страниц, предлагаемых сервером ZebraNet, и, например, alert () - сообщение пользователю в браузере. Это означает, что мне сначала нужно получить эту html-страницу в Javascript. Хотя принтер находится в локальной сети компьютера пользователя, та же политика происхождениявсе еще твердо стоит на моем пути. Я пробовал JSONP, но сервер возвращает html, и я не нашел способа изменить его функциональность (если бы мог, я бы уже установил волшебный заголовок Access-control-allow-origin: *). Поэтому я решил написать небольшое консольное приложение на C #. Для правильной работы он должен запускаться от имени администратора, иначе он будет: D исключение. Вот некоторый код:

// Create a listener.
        HttpListener listener = new HttpListener();
        // Add the prefixes.
        //foreach (string s in prefixes)
        //{
        //    listener.Prefixes.Add(s);
        //}
        listener.Prefixes.Add("http://*:1234/"); // accept connections from everywhere,
        //because the printer is accessible only within the LAN (no portforwarding)
        listener.Start();
        Console.WriteLine("Listening...");
        // Note: The GetContext method blocks while waiting for a request. 
        HttpListenerContext context;
        string urlForRequest = "";

        HttpWebRequest requestForPage = null;
        HttpWebResponse responseForPage = null;
        string responseForPageAsString = "";

        while (true)
        {
            context = listener.GetContext();
            HttpListenerRequest request = context.Request;
            urlForRequest = request.RawUrl.Substring(1, request.RawUrl.Length - 1); // remove the slash, which separates the portNumber from the arg sent
            Console.WriteLine(urlForRequest);

            //Request for the html page:
            requestForPage = (HttpWebRequest)WebRequest.Create(urlForRequest);
            responseForPage = (HttpWebResponse)requestForPage.GetResponse();
            responseForPageAsString = new StreamReader(responseForPage.GetResponseStream()).ReadToEnd();

            // Obtain a response object.
            HttpListenerResponse response = context.Response;
            // Send back the response.
            byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseForPageAsString);
            // Get a response stream and write the response to it.
            response.ContentLength64 = buffer.Length;
            response.AddHeader("Access-Control-Allow-Origin", "*"); // the magic header in action ;-D
            System.IO.Stream output = response.OutputStream;
            output.Write(buffer, 0, buffer.Length);
            // You must close the output stream.
            output.Close();
            //listener.Stop();

Все, что нужно сделать пользователю, - это запустить это консольное приложение от имени администратора. Я знаю, что это тоже ... неприятно и сложно, но это своего рода обходной путь к проблеме политики домена в случае, если вы не можете каким-либо образом изменить сервер.

изменить: из js я делаю простой вызов ajax:

$.ajax({
                type: 'POST',
                url: 'http://LAN_IP:1234/http://google.com',
                success: function (data) {
                    console.log("Success: " + data);
                },
                error: function (e) {
                    alert("Error: " + e);
                    console.log("Error: " + e);
                }
            });

HTML-код запрошенной страницы возвращается и сохраняется в переменной данных .


0

Чтобы получить данные с внешнего сайта, используя локальный прокси-сервер, как предлагает jherax, вы можете создать страницу php, которая извлекает контент для вас с соответствующего внешнего URL-адреса, а затем отправляет запрос на получение этой странице php.

var req = new XMLHttpRequest();
req.open('GET', 'http://localhost/get_url_content.php',false);
if(req.status == 200) {
   alert(req.responseText);
}

в качестве прокси-сервера php вы можете использовать https://github.com/cowboy/php-simple-proxy


0

В URLнаши дни ваш код не работает, но ваш код можно обновить с помощью этого рабочего решения:

var url = "http://saskatchewan.univ-ubs.fr:8080/SASStoredProcess/do?_username=DARTIES3-2012&_password=P@ssw0rd&_program=%2FUtilisateurs%2FDARTIES3-2012%2FMon+dossier%2Fanalyse_dc&annee=2012&ind=V&_action=execute";

url = 'https://google.com'; // TEST URL

$.get("https://images"+~~(Math.random()*33)+"-focus-opensocial.googleusercontent.com/gadgets/proxy?container=none&url=" + encodeURI(url), function(data) {
    $('div.ajax-field').html(data);
});
<div class="ajax-field"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


-2

Вам нужен прокси-сервер CORS, который передает ваш запрос из вашего браузера для запроса службы с соответствующими заголовками CORS . Список таких сервисов представлен во фрагменте кода ниже. Вы также можете запустить предоставленный фрагмент кода, чтобы увидеть связь с такими службами из вашего местоположения.

$('li').each(function() {
  var self = this;
  ping($(this).text()).then(function(delta) {
    console.log($(self).text(), delta, ' ms');
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/jdfreder/pingjs/c2190a3649759f2bd8569a72ae2b597b2546c871/ping.js"></script>
<ul>
  <li>https://crossorigin.me/</li>
  <li>https://cors-anywhere.herokuapp.com/</li>
  <li>http://cors.io/</li>
  <li>https://cors.5apps.com/?uri=</li>
  <li>http://whateverorigin.org/get?url=</li>
  <li>https://anyorigin.com/get?url=</li>
  <li>http://corsproxy.nodester.com/?src=</li>
  <li>https://jsonp.afeld.me/?url=</li>
  <li>http://benalman.com/code/projects/php-simple-proxy/ba-simple-proxy.php?url=</li>
</ul>


11
Это никоим образом не отвечает на вопрос.
0xc0de 06

@ 0xc0de я наконец написал ответ.
galeksandrp

-7

Догадаться. Вместо этого использовал это.

$('.div_class').load('http://en.wikipedia.org/wiki/Cross-origin_resource_sharing #toctitle');

Код, который вы там использовали, не имеет значения. Важны заголовки CORS на стороне сервера.
Quentin
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.