Каковы методы и внедрения внешнего междоменного интерфейса?

внешний интерфейс

1. Политика того же происхождения выглядит следующим образом:

URL иллюстрировать Разрешить ли общение
www.a.com/a.js www.a.com/b.js под тем же доменным именем разрешать
www.a.com/lab/a.js www.a.com/script/b.js Разные папки под одним доменным именем разрешать
www.a.com:8000/a.js www.a.com/b.js То же доменное имя, другой порт не положено
www.a.com/a.js www.a.com/b.js То же доменное имя, другой протокол не положено
www.a.com/a.js http://70.32.92.74/b.js Доменное имя и доменное имя, соответствующее ip не положено
www.a.com/a.js script.a.com/b.js Основной домен тот же, поддомены разные не положено
www.a.com/a.js a.com/b.js То же доменное имя, разные доменные имена второго уровня (как указано выше) Не разрешено (в этом случае файлы cookie не разрешают доступ)
www.cnblogs.com/a.js www.a.com/b.js разные доменные имена не положено

Особое внимание к двум точкам:
Во-первых: если это междоменная проблема, вызванная протоколами и портами, «передний план» бессилен.
Во-вторых: в междоменной проблеме домен идентифицируется только «заголовком URL-адреса» без попытки определить, соответствует ли один и тот же IP-адрес двум доменам или два домена находятся на одном и том же IP-адресе.
«URL первого» относится к window.location.protocol + window.location.host, что можно понимать как «Домены, протоколы и порты должны совпадать».

Внешний интерфейс решает междоменные проблемы

1> document.domain + iframe (этот метод можно использовать только в том случае, если основной домен тот же)

(1) На сайте www.a.com/a.html:

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://www.script.a.com/b.html';
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){
    var doc = ifr.contentDocument || ifr.contentWindow.document;
    //在这里操作doc,也就是b.html
    ifr.onload = null;
};

(2) На сайте www.script.a.com/b.html:

document.domain = 'a.com';

2> Динамически создавать скрипт

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

function loadScript(url, func) {
  var head = document.head || document.getElementByTagName('head')[0];
  var script = document.createElement('script');
  script.src = url;

  script.onload = script.onreadystatechange = function(){
    if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){
      func();
      script.onload = script.onreadystatechange = null;
    }
  };

  head.insertBefore(script, 0);
}
window.baidu = {
  sug: function(data){
    console.log(data);
  }
}
loadScript('http://suggestion.baidu.com/su?wd=w',function(){console.log('loaded')});
//我们请求的内容在哪里?
//我们可以在chorme调试面板的source中看到script引入的内容

3> location.hash + iframe

Принцип заключается в использовании location.hash для передачи значений.

Предположим, что файл cs1.html под доменным именем a.com должен передавать информацию вместе с файлом cs2.html под доменным именем cnblogs.com.
1) cs1.html сначала создает скрытый iframe, src iframe указывает на страницу cs2.html под доменным именем cnblogs.com
2) После того, как cs2.html ответит на запрос, он передаст данные, изменив хеш-значение cs1.html.
3) В то же время добавьте таймер в cs1.html, чтобы определить, изменилось ли значение location.hash через определенный период времени.Как только произойдет изменение, получите значение хеш-функции.
Примечание. Поскольку две страницы находятся в разных доменах, IE и Chrome не позволяют изменять значение parent.location.hash, поэтому необходимо использовать прокси iframe под доменным именем a.com.
код показывает, как показано ниже:
Во-первых, это файл cs1.html в домене a.com:

function startRequest(){
    var ifr = document.createElement('iframe');
    ifr.style.display = 'none';
    ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
    document.body.appendChild(ifr);
}

function checkHash() {
    try {
        var data = location.hash ? location.hash.substring(1) : '';
        if (console.log) {
            console.log('Now the data is '+data);
        }
    } catch(e) {};
}
setInterval(checkHash, 2000);

cs2.html под доменным именем cnblogs.com:

//模拟一个简单的参数处理操作
switch(location.hash){
    case '#paramdo':
        callBack();
        break;
    case '#paramset':
        //do something……
        break;
}

function callBack(){
    try {
        parent.location.hash = 'somedata';
    } catch (e) {
        // ie、chrome的安全机制无法修改parent.location.hash,
        // 所以要利用一个中间的cnblogs域下的代理iframe
        var ifrproxy = document.createElement('iframe');
        ifrproxy.style.display = 'none';
        ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下
        document.body.appendChild(ifrproxy);
    }
}

Доменное имя cs3.html под a.com

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

4> window.name + iframe

Прелесть window.name: значение имени сохраняется при загрузке страницы (даже в разных доменах) и может поддерживать очень длинные значения имени (2 МБ).

1) Создайте a.com/cs1.html

2) Создайте a.com/proxy.html и добавьте следующий код

<head>
  <script>
  function proxy(url, func){
    var isFirst = true,
        ifr = document.createElement('iframe'),
        loadFunc = function(){
          if(isFirst){
            ifr.contentWindow.location = 'http://a.com/cs1.html';
            isFirst = false;
          }else{
            func(ifr.contentWindow.name);
            ifr.contentWindow.close();
            document.body.removeChild(ifr);
            ifr.src = '';
            ifr = null;
          }
        };

    ifr.src = url;
    ifr.style.display = 'none';
    if(ifr.attachEvent) ifr.attachEvent('onload', loadFunc);
    else ifr.onload = loadFunc;

    document.body.appendChild(iframe);
  }
</script>
</head>
<body>
  <script>
    proxy('http://www.baidu.com/', function(data){
      console.log(data);
    });
  </script>
</body>

3 в b.com/cs1.html:

<script>
    window.name = '要传送的内容';
</script>

5> postMessage (API в XMLHttpRequest уровня 2 в HTML5)

(1) Код на a.com/index.html:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样
                                        // 若写成'http://c.com'就不会执行postMessage了
    ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

(2) B.com/index.html код:

<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"I was there!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但由于同源策略,这里event.source不可以访问window对象
        }
    }, false);
</script>

6> CORS

Идея CORS состоит в том, чтобы использовать настраиваемые заголовки HTTP, чтобы браузер мог взаимодействовать с сервером, чтобы решить, должен ли запрос или ответ быть успешным или нет.
Реализация CORS в IE — это xdr.

var xdr = new XDomainRequest();
xdr.onload = function(){
    console.log(xdr.responseText);
}
xdr.open('get', 'http://www.baidu.com');
......
xdr.send(null);

Реализация в других браузерах в XHR

var xhr =  new XMLHttpRequest();
xhr.onreadystatechange = function () {
    if(xhr.readyState == 4){
        if(xhr.status >= 200 && xhr.status < 304 || xhr.status == 304){
            console.log(xhr.responseText);
        }
    }
}
xhr.open('get', 'http://www.baidu.com');
......
xhr.send(null);

Кросс-браузер CORS

function createCORS(method, url){
    var xhr = new XMLHttpRequest();
    if('withCredentials' in xhr){
        xhr.open(method, url, true);
    }else if(typeof XDomainRequest != 'undefined'){
        var xhr = new XDomainRequest();
        xhr.open(method, url);
    }else{
        xhr = null;
    }
    return xhr;
}
var request = createCORS('get', 'http://www.baidu.com');
if(request){
    request.onload = function(){
        ......
    };
    request.send();
}

7> JSONP

JSONP состоит из двух частей: функции обратного вызова и данных.

Функция обратного вызова — это функция, которая будет вызываться на текущей странице, когда приходит ответ.

Данные — это данные json, переданные в функцию обратного вызова, то есть параметры функции обратного вызова.

function handleResponse(response){
    console.log('The responsed data is: '+response.data);
}
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json/?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);
/*handleResonse({"data": "zhe"})*/
//原理如下:
//当我们通过script标签请求时
//后台就会根据相应的参数(json,handleResponse)
//来生成相应的json数据(handleResponse({"data": "zhe"}))
//最后这个返回的json数据(代码)就会被放在当前js文件中被执行
//至此跨域通信完成

Хотя jsonp очень прост, он имеет следующие недостатки:

(1) Проблемы безопасности (в коде запроса могут быть угрозы безопасности)

(2) Нелегко определить, не удается ли выполнить запрос JSONP

8> web sockets

WebSockets — это API браузера, целью которого является обеспечение полнодуплексной двусторонней связи через одно постоянное соединение. (Политика того же происхождения не применяется к веб-сокетам)

Принцип веб-сокетов: после того, как JS создаст веб-сокет, в браузер будет отправлен HTTP-запрос для инициации соединения. После получения ответа сервера происходит обмен установленным соединением с протокола HTTP на протокол веб-сокета с использованием HTTP-апгрейда.

Он корректно работает только на серверах, поддерживающих протокол websocket.

var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
    var data = event.data;
}