https://www.googleapis.com/upload/drive/v2/files真的支持CORS吗?

时间:2012-07-23 17:12:22

标签: google-drive-api cors

更新:这是GoogleDrive中的错误,未启用CORS上传URI。 @Nivco向我指出了使用iframe和代理(不是CORS)的Google客户端库。我将(经过测试的)工作代码放在底部,并附上详细说明。请参阅下面的答案。

Inserting File to Google Drive through APIAuthorization of Google Drive using JavaScript表示上传端点支持CORS,但我无法使用它们。我可以使用Files: insert获取授权并插入一个空文件,但我无法上传内容 - 当我使用https://www.googleapis.com/upload/drive/v2/files时,我得到405(不允许方法)错误在插入文件堆栈溢出帖子中的示例中给出的两种技术。

CORS是否可能适用于v1且尚未启用v2?

编辑:顺便说一句,405错误发生在Chrome正在进行的OPTIONS请求上。

编辑:以下是我尝试过的代码:

在我提出代码之前,我想强调一下,我能够对文件进行身份验证和列出。我只是无法将数据上传到文件。

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错误。没有POST,因为Chrome无法继续,因为其OPTIONS请求因405而失败,因此它会在控制台中输出此错误:

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.

3 个答案:

答案 0 :(得分:2)

看起来你是对的,上传API端点似乎不支持CORS请求,而其他端点确实支持它(很抱歉未经过彻底测试)。这是一个错误,我们让工程团队知道这个问题。

与此同时,似乎唯一的解决方法是使用Javascript客户端库并利用它使用的iframe代理,如Authorization of Google Drive using JavaScript

中所述

感谢你提出这个问题!

答案 1 :(得分:2)

CORS现已完全启用。有关如何使用vanilla JS进行可恢复上传的示例,请参阅https://github.com/googledrive/cors-upload-sample

答案 2 :(得分:0)

这个答案(事实上问题本身)现在已经多余,因为Steve Bazyl确认了完整的CORS支持

工作代码,使用@ Nivco的帮助,以及详细说明:

这是完整测试此技术的工作代码。要使用它,您需要制作两页。第一页验证并启动第二页,这是您的实际应用程序。为了能够访问Google云端硬盘API以上传文件,您需要注册一个应用,其描述为here

您的第一页将使用OAuth,this Stackoverflow answer中对此进行了描述。它会使用如下所示的片段调用您的应用:

#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客户端库将a\na\b\n上传到GoogleDrive中名为leisureUpload的文件的示例应用。不需要使用任何gapi.auth方法,因为它直接在调用中使用带有Authorization头的原始gapi.client.request()调用,就像使用CORS的xmlHttpRequest()一样:

<!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>