Получение изображений контактов Google на стороне клиента

Я получаю контакты Google в веб-приложении с помощью Google JavaScript API и хочу получить их изображения.

Я делаю что-то вроде этого (сильно упрощенный):

var token; // let's admit this is available already

function getPhotoUrl(entry, cb) {
  var link = entry.link.filter(function(link) {
    return link.type.indexOf("image") === 0;
  }).shift();
  if (!link)
    return cb(null);
  var request = new XMLHttpRequest();
  request.open("GET", link.href + "?v=3.0&access_token=" + token, true);
  request.responseType = "blob";
  request.onload = cb;
  request.send();
}

function onContactsLoad(responseText) {
  var data = JSON.parse(responseText);
  (data.feed.entry || []).forEach(function(entry) {
    getPhotoUrl(e, function(a, b, c) {
      console.log("pic", a, b, c);
    });
  });
}

Но я получаю эту ошибку как в Chrome, так и в Firefox:

Запросы между источниками заблокированы: политика того же источника запрещает чтение удаленного ресурса по адресу https://www.google.com/m8/feeds/photos/media/‹user_email>/‹some_contact_id>?v=3.0&access_token=‹obfuscated>. Это можно исправить, переместив ресурс в тот же домен или включив CORS.

Глядя на заголовки ответа от конечной точки каналов/фотографий, я вижу, что Access-Control-Allow-Origin: * не отправляется, поэтому я получаю ошибку CORS.

Обратите внимание, что Access-Control-Allow-Origin: * отправляется при достижении конечной точки feeds/contacts, что позволяет выполнять междоменные запросы.

Это ошибка, или я что-то пропустил из их документов?


person NiKo    schedule 20.01.2014    source источник


Ответы (2)


Предполагая, что вам нужно только «изображение профиля», попробуйте переместить запрос на это изображение непосредственно в HTML, установив полный URL-адрес в качестве элемента src тега <img>?access_token=<youknowit> в конце).

Например. используя Angular.js

<img ng-src="{{contact.link[1].href + tokenForImages}}" alt="photo" />

Что касается CORS в целом, кажется, что есть немало мест, где доступ к API из JS не работает должным образом.

Надеюсь это поможет.

person bjoernklose    schedule 01.06.2014

Пока не могу комментировать, поэтому этот ответ…

Очевидно, вы уже настроили правильный идентификатор клиента и источники JavaScript в консоли разработчиков Google.

Похоже, что API общих контактов домена не работает так, как рекламируется, и соблюдает свое обещание CORS только тогда, когда вы запрашиваете данные JSONP (ваш код указывает, что вы получили данные ввода с помощью JSON). Для формата JSON API устанавливает access-control-allow-origin в * вместо источников JavaScript, которые вы указываете для своего проекта.

Но на сегодняшний день (16.06.2015), если вы попытаетесь выдать GET, POST… с другим типом данных (например, atom/xml), API Google вообще не установит происхождение контроля доступа. , поэтому ваш браузер отклонит ваш запрос на доступ к данным (ошибка 405).

Это явно ошибка, которая предотвращает любое программное использование API общих контактов, кроме простого списка записей: больше нельзя создавать, обновлять, удалять записи или получать доступ к фотографиям.

Пожалуйста, поправьте меня, если я ошибаюсь (хотел бы я ошибаться); пожалуйста, прокомментируйте или отредактируйте, если вы знаете, как лучше всего сообщить об этой ошибке в Google.

Обратите внимание: для полноты картины вот скелет кода, который я использую для доступа к контактам (требуется jQuery).

    <button id="authorize-button" style="visibility: hidden">Authorize</button>
    <script type="text/javascript">
        var clientId = 'TAKE-THIS-FROM-CONSOLE.apps.googleusercontent.com',
            apiKey = 'TAKE-THAT-FROM-GOOGLE-DEVELOPPERS-CONSOLE',
            scopes = 'https://www.google.com/m8/feeds';
        // Use a button to handle authentication the first time.
        function handleClientLoad () {
            gapi.client.setApiKey ( apiKey );
            window.setTimeout ( checkAuth, 1 );
        }
        function checkAuth() {
            gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
        }
        function handleAuthResult ( authResult ) {
            var authorizeButton = document.getElementById ( 'authorize-button' );
            if ( authResult && !authResult.error ) {
                authorizeButton.style.visibility = 'hidden';
                var cif = {
                    method: 'GET',
                    url:  'https://www.google.com/m8/feeds/contacts/mydomain.com/full/',
                    data: {
                        "access_token": authResult.access_token,
                        "alt":          "json",
                        "max-results":  "10"
                    },
                    headers: { 
                        "Gdata-Version":    "3.0"    
                    },
                    xhrFields: {
                        withCredentials: true
                    },
                    dataType: "jsonp"
                };
                $.ajax ( cif ).done ( function ( result ) {
                        $ ( '#gcontacts' ).html ( JSON.stringify ( result, null, 3 ) );
                } );
            } else {
                authorizeButton.style.visibility = '';
                authorizeButton.onclick = handleAuthClick;
            }
        }
        function handleAuthClick ( event ) {
            gapi.auth.authorize ( { client_id: clientId, scope: scopes, immediate: false }, handleAuthResult );
            return false;
        }
    </script>
    <script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
    <pre id="gcontacts"></pre>

Если вы замените cif.data.alt на atom и/или cif.dataType на xml, вы получите печально известную ошибку 405.

ps: cif, конечно же, связан с ajax ;-)

person Jean-Rene Bouvier    schedule 16.06.2015