Загрузка междоменной конечной точки с помощью 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.