API Google Picker работает в Safari, но не работает в Chrome

Я разрабатываю веб-приложение в Flask и пытаюсь использовать API Google Picker, чтобы пользователь мог выбрать файл на своем Google Диске. Ниже приведен мой код для тестирования API Picker (код адаптирован из https://gist.github.com/Daniel15/5994054).

Вот html-файл (без личных идентификаторов):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Google Drive File Picker Example</title>
</head>
<body>
    <button type="button" id="pick">Pick File</button>
  <script src="../static/gdrive-filepicker.js"></script>
  <script>
    function initPicker() {
      var picker = new FilePicker({
        apiKey: '<Complete with API key>',
        clientId: <Complete with numerical clientId>,
        buttonEl: document.getElementById('pick'),
        onSelect: function(file) {
          console.log(file);
          alert('Selected ' + file.title);
        }
      });
    }
  </script>
</body>

</html>

<script src="https://www.google.com/jsapi?key=<completed with key>"></script>
<script src="https://apis.google.com/js/client.js?onload=initPicker"></script>

И вот файл javascript:

(function() {
/**
 * Initialise a Google Driver file picker
 */
var FilePicker = window.FilePicker = function(options) {
    // Config
    this.apiKey = options.apiKey;
    this.clientId = options.clientId;

    // Elements
    this.buttonEl = options.buttonEl;

    // Events
    this.onSelect = options.onSelect;
    this.buttonEl.addEventListener('click', this.open.bind(this));

    // Disable the button until the API loads, as it won't work properly until then.
    this.buttonEl.disabled = true;

    // Load the drive API
    gapi.client.setApiKey(this.apiKey);
    gapi.client.load('drive', 'v2', this._driveApiLoaded.bind(this));
    google.load('picker', '1', { callback: this._pickerApiLoaded.bind(this) });
}

FilePicker.prototype = {
    /**
     * Open the file picker.
     */
    open: function() {
        // Check if the user has already authenticated
        var token = gapi.auth.getToken();
        if (token) {
            this._showPicker();
        } else {
            // The user has not yet authenticated with Google
            // We need to do the authentication before displaying the Drive picker.
            this._doAuth(false, function() { this._showPicker(); }.bind(this));
        }
    },

    /**
     * Show the file picker once authentication has been done.
     * @private
     */
    _showPicker: function() {
        var accessToken = gapi.auth.getToken().access_token;
        this.picker = new google.picker.PickerBuilder().
            addView(google.picker.ViewId.SPREADSHEETS).
            setAppId(this.clientId).
            setOAuthToken(accessToken).
            setCallback(this._pickerCallback.bind(this)).
            //setOrigin(google.script.host.origin).
            build().
            setVisible(true);
    },

    /**
     * Called when a file has been selected in the Google Drive file picker.
     * @private
     */
    _pickerCallback: function(data) {
        if (data[google.picker.Response.ACTION] == google.picker.Action.PICKED) {
            var file = data[google.picker.Response.SPREADSHEETS][0],
                id = file[google.picker.Document.ID],
                request = gapi.client.drive.files.get({
                    fileId: id
                });

            request.execute(this._fileGetCallback.bind(this));
        }
    },
    /**
     * Called when file details have been retrieved from Google Drive.
     * @private
     */
    _fileGetCallback: function(file) {
        if (this.onSelect) {
            this.onSelect(file);
        }
    },

    /**
     * Called when the Google Drive file picker API has finished loading.
     * @private
     */
    _pickerApiLoaded: function() {
        this.buttonEl.disabled = false;
    },

    /**
     * Called when the Google Drive API has finished loading.
     * @private
     */
    _driveApiLoaded: function() {
        this._doAuth(true);
    },

    /**
     * Authenticate with Google Drive via the Google JavaScript API.
     * @private
     */
    _doAuth: function(immediate, callback) {
        gapi.auth.authorize({
            client_id: this.clientId + '<complete with second part of client id>.apps.googleusercontent.com',
            scope: 'https://www.googleapis.com/auth/drive.readonly',
            immediate: immediate
        }, callback);
    }
};
}());

Когда я запускаю это в Safari, все работает нормально, однако в Chrome происходит сбой с перенаправлением 401. Ошибка регистрируется в Chrome:

Completed initPicker()
Uncaught null
Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://docs.google.com') does not match the recipient window's origin ('http://localhost:8081').
Invalid 'X-Frame-Options' header encountered when loading 'https://docs.google.com/picker?protocol=gadgets&origin=http%3A%2F%2Flocalho…adsheets%22))&rpctoken=bmrqgq5vh5h&rpcService=k3a915ai4cgk&thirdParty=true': 'ALLOW-FROM http://localhost:8081' is not a recognized directive. The header will be ignored.
GET https://docs.google.com/picker?protocol=gadgets&origin=http%3A%2F%2Flocalho…adsheets%22))&rpctoken=bmrqgq5vh5h&rpcService=k3a915ai4cgk&thirdParty=true 401 ()

И логи из Safari:

[Error] Unable to post message to https://docs.google.com. Recipient has origin http://localhost:8081.
[Error] Invalid 'X-Frame-Options' header encountered when loading 'https://docs.google.com/picker?protocol=gadgets&origin=http%3A%2F%2Flocalhost%3A8081&oauth_token=ya29..vgIMhRk5EJ9sBOEppY9NbkFpujbhPBvsUoEDJB85OW6ED9Gnfx2PK8N1U1W-zPVvSSs&hostId=localhost&relayUrl=http%3A%2F%2Flocalhost%3A8081%2Ffavicon.ico&nav=((%22spreadsheets%22))&rpctoken=oox715usn81y&rpcService=m5rgot68gsh3&thirdParty=true': 'ALLOW-FROM http://localhost:8081' is not a recognized directive. The header will be ignored.

Этот ответ (https://stackoverflow.com/questions/27573017/failed-to-execute-postmessage-on-domwindow-https-www-youtube-com-http) кажется, что это связано с разницей в протоколе между https и http, но я нахожу это странным, что это будет работать в Safari, но не в Chrome. Я также безуспешно пытался использовать .setOrigin(window.location.protocol + '//' + window.location.host). Любые идеи? Спасибо!


person Hatsy    schedule 08.04.2016    source источник
comment
Удалось ли вам обойти эту проблему?   -  person being_j    schedule 18.12.2020