3

更新:これは GoogleDrive のバグです。アップロード URI に対して CORS が有効になっていません。@Nivco は、iframe とプロキシ (CORS ではない) を使用する Google のクライアント ライブラリの回避策を教えてくれました。詳細な説明とともに、(テスト済みの) 動作コードを一番下に置きます。例については、以下の回答を参照してください。

Inserting File to Google Drive through APIAuthorization of Google Drive using JavaScriptは、アップロード エンドポイントが CORS をサポートしていると言っていますが、私はそれらを使用できませんでした。Files: insertを使用して承認を取得し、空のファイルを挿入できますが、コンテンツをアップロードできません。https://www.googleapis.com/uploadを使用すると、405 (メソッドが許可されていません) エラーが発生します。 /drive/v2/filesは、ファイル スタック オーバーフローの挿入の投稿の例に示されている 2 つの手法のいずれかを使用した場合です。

CORS が v1 で機能し、v2 で有効になっていない可能性はありますか?

EDIT:ちなみに、405エラーはchromeが作成しているOPTIONSリクエストにあります。

編集:これが私の試みの1つからのコードです:

コードを提示する前に、ファイルを認証して一覧表示できることを強調したいと思います。ファイルにデータをアップロードできません。

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart');
xhr.setRequestHeader('Authorization', 'Bearer ' + params.access_token);
xhr.setRequestHeader("Content-Type",  'multipart/related; boundary="END_OF_PART"');
xhr.onreadystatechange = function(data) {
  if (xhr.readyState == DONE) {
    document.getElementById("files").innerHTML = "Uploaded file: " + xhr.responseText;
    };
  }
xhr.send([
  mimePart("END_OF_PART", "application/json", json),
  mimePart("END_OF_PART", "text/plain", "a\nb\n"),
  "\r\n--END_OF_PART--\r\n",
].join(''));
function mimePart(boundary, mimeType, content) {
  return [
    "\r\n--", boundary, "\r\n",
    "Content-Type: ", mimeType, "\r\n",
    "Content-Length: ", content.length, "\r\n",
    "\r\n",
    content,
  ].join('');
}

リクエストは次のとおりです。

Request URL:https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart
Request Method:OPTIONS

応答は次のとおりです。

Status Code:405 Method Not Allowed
cache-control:no-cache, no-store, must-revalidate
content-length:0
content-type:text/html; charset=UTF-8
date:Mon, 23 Jul 2012 22:41:29 GMT
expires:Fri, 01 Jan 1990 00:00:00 GMT
pragma:no-cache
server:HTTP Upload Server Built on Jul 17 2012 16:15:04 (1342566904)
status:405 Method Not Allowed
version:HTTP/1.1

Chrome はその OPTIONS リクエストに対して 405 エラーを受け取るため、応答はありません。OPTIONS リクエストが 405 で失敗したため、Chrome が続行できないため、POST はありません。コンソールに次のエラーが出力されます。

XMLHttpRequest cannot load https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart. Origin https://leisurestorage.appspot.com is not allowed by Access-Control-Allow-Origin.
4

3 に答える 3

2

おっしゃる通り、アップロード API エンドポイントは CORS リクエストをサポートしていないようですが、他のエンドポイントはサポートしています (完全にテストしていないことをお詫びします)。これはバグであり、エンジニアリング チームにこの問題を知らせました。

当面の唯一の回避策は、JavaScript を使用したGoogle ドライブの承認で説明されているように、Javascript クライアント ライブラリを使用し、それが使用する iframe プロキシを利用することです。

これを取り上げてくれてありがとう!

于 2012-07-24T00:03:49.280 に答える
0

Steve Bazylが確認したように、CORSが完全にサポートされているため、この回答(および実際には質問自体)は冗長になりました

詳細な説明とともに、@Nivcoのヘルプを使用した作業コード:

この手法の完全なテストの作業コードを次に示します。これを使用するには、2 つのページを作成する必要があります。最初のページは、実際のアプリである 2 番目のページを認証して起動します。Google Drive API にアクセスしてファイルをアップロードできるようにするには、こちらで説明されているアプリを登録する必要があります。

最初のページでは、この Stackoverflow answerで説明されている OAuth を使用します。次のようなフラグメントでアプリを呼び出します。

#access_token=ya29.AHES6ZSb4M4ju8U_X_zgFrz_MD2RsjrQu5V05HjsBtrCl0nh2SrnaA&token_type=Bearer&expires_in=3600

JavaScript では、 でそのフラグメントにアクセスできますlocation.hash。値を保存したら、location.hashすぐに空の文字列に設定して、ブラウザーのロケーション バーに表示されないようにすることをお勧めします。アプリは、CORS リクエストでフラグメントからの access_token の値を使用する必要があり、アップロード API へのプロキシされた (非 CORS) リクエストでも使用する必要があります。以下は起動ページの例です。これは、実際には OAuth の例のコードの単なるバージョンです。

<html>
  <body>
    <a href="javascript:poptastic('https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.file&client_id=270759921607.apps.googleusercontent.com&redirect_uri=https://leisurestorage.appspot.com&response_type=token');">Authorize Leisure Storage</a><br>
    <script>
      function poptastic(url) {
        var newWindow = window.open(url, 'name', 'height=600,width=450');
        if (window.focus) {
          newWindow.focus();
        }
      }
    </script>
  </body>
</html>

これは、 Google の JavaScript 用クライアント ライブラリを使用して、GoogleDrive でa\na\b\n呼び出されたファイルにアップロードするアプリの例です。leisureUploadCORS を使用して xmlHttpRequest() を使用する場合と同様に、呼び出しで Authorization ヘッダーを使用して生の gapi.client.request() 呼び出しを直接使用するため、gapi.auth メソッドを使用する必要はありません。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Leisure</title>
    <script type="text/javascript">
    var hash = location.hash.substring(1).split('&');
    location.hash = '';
    var params = {};

    for (var i = 0; i < hash.length; i++) {
        var p = hash[i].split('=');

        params[p[0]] = p[1];
    }
    function gapiClientLoaded() {/* do nothing */}
    function uploadTestFile() {
        var json = JSON.stringify({
            mimeType: 'text/plain',
            title: 'leisureUpload',
        });
        var xhr = new XMLHttpRequest();

        gapi.client.request({
            'path': '/upload/drive/v1/files',
            'method': 'POST',
            'params': {'uploadType': 'multipart'},
            'headers': {
                'Content-Type': 'multipart/mixed; boundary="END_OF_PART"',
                'Authorization': 'Bearer ' + params.access_token,
            },
            'body': [
                mimePart("END_OF_PART", "application/json", json),
                mimePart("END_OF_PART", "text/plain", "a\nb\n"),
                "\r\n--END_OF_PART--\r\n",
            ].join('')
        }).execute(function(file) {
            document.getElementById("result").innerHTML = "Uploaded file: " + file;
        });
    }
    function mimePart(boundary, mimeType, content) {
        return [
            "\r\n--", boundary, "\r\n",
            "Content-Type: ", mimeType, "\r\n",
            "Content-Length: ", content.length, "\r\n",
            "\r\n",
            content,
        ].join('');
    }
    </script>
    <script src="https://apis.google.com/js/client.js?onload=gapiClientLoaded"></script>
  </head>
  <body>
    <h1>Welcome to Leisure!</h1>
    <button onclick="uploadTestFile()">Upload Test File</button><br>
    <pre id="result"></pre>
  </body>
</html>
于 2012-07-25T20:06:32.803 に答える