写入Google Spreadsheet API时,CORS预检失败 [英] CORS preflight fails when writing to Google Spreadsheet API

查看:95
本文介绍了写入Google Spreadsheet API时,CORS预检失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用Google电子表格的JS应用程序.我使用OAuth授权通过REST接口访问它们,当我坚持阅读所用的GET请求时,一切都很好.

I'm working on a JS application that uses Google spreadsheets. I access them via the REST interface using OAuth authorization, and all is well and good when I stick to GET requests used for reading.

我想使用文档中中显示的API添加新工作表.这需要带有相当奇怪的Content-type: application/atom+xmlPOST请求,我确实喜欢这样(JQuery):

I'd like to add a new worksheet using the API shown in the docs. This requires a POST request with the rather strange Content-type: application/atom+xml, which I do like this (JQuery):

$.ajax("https://spreadsheets.google.com/feeds/worksheets/{{key}}/private/full", {
  type: "POST",
  contentType: "application/atom+xml",
  headers: { Authorization: "Bearer" + token },
  data: data
});

由于CORS的要求,这使Chrome发出了飞行前请求.预检OPTIONS请求失败-Google在响应中不包含Access-Control-Allow-Origin标头,而Chrome拒绝前进:

This makes Chrome issue a preflight request due to CORS requirements. The preflight OPTIONS request fails - Google does not include Access-Control-Allow-Origin headers in the response, and Chrome refuses to go forward:

OPTIONS https://spreadsheets.google.com/feeds/.../private/full 
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

但是,如果我直接将GET指向相同的URL(这实际上是您读取电子表格的方式),那么我会执行获取Access-Control-*标头,这意味着对CORS的支持是故意的.具有标准内容类型(如text/plain)且不会触发预检OPTIONSPOST请求也是如此-我得到了CORS标头(即使请求失败是针对错误的内容类型).

However, if I make a straight GET to the same URL (this is actually how you read the spreadsheet), I do get the Access-Control-* headers, which means that CORS support was intended. The same with POST requests with standard content types (like text/plain) which don't trigger a preflight OPTIONS - I get the CORS headers (even though the request fails do to the bad content type).

有人知道如何解决此问题,还是从浏览器中解决该问题的正确"方法?另外,指向能够从浏览器内JS向Google电子表格执行写入"操作的任何工作代码的指针也将非常有用.

Does anybody have an idea how to work around this problem, or the "correct" way to do it from a browser? Alternatively, a pointer towards any piece of working code that is able to do 'write' operations to Google spreadsheets from in-browser JS would also be great.

我希望仅在可能的情况下将此应用程序保留在客户端-我了解到,通过处理Google API交互的服务器端组件,这件事会变得更容易.

I would like to keep this application client-side only if possible - I understand that with a server-side component handling Google API interaction, this thing would be easier.

推荐答案

别管我上面写的内容.那只是部分时间解决了.看来Google Sheets API根本不一直支持CORS.我写了一个服务器端代理,它仅将请求传递到google.com,这是前进的唯一方法.

Never mind what I wrote above. That only solves it part of the time. It seems Google Sheets API simply doesn't support CORS consistently. I wrote a server-side proxy which only passes requests through to google.com, that being the only way forward.

我想分享我的js代码,因为我写了一个不错的小东西,可以像$ .ajax一样使用.也很高兴分享服务器端代码,但是您可以使用类似这样的东西与您自己的服务器端代理进行接口.它不是很漂亮,但是可以正常工作.哦,嗯,​​LGPL.这是js:

I thought I'd share my js code, because I wrote a nice little thing that can be used just like $.ajax. Also glad to share the server-side code too, but you could use something like this to interface with your own server-side proxy. It's not pretty but it is working. Oh, um, LGPL. Here's the js:

//  ####    ####   #####    ####     ##    ##   ##    ##   ##  ##
// ##  ##  ##  ##  ##  ##  ##       ####   ##   ##   ####  ##  ##
// ##      ##  ##  #####    ####   ##  ##  ## # ##  ##  ##  ####
// ##  ##  ##  ##  ## ##       ##  ######  #######  ######   ##
//  ####    ####   ##  ##   ####   ##  ##   ## ##   ##  ##   ##

function CorsAway(serverSideUrl) {
    // Server-side proxy handling of cross-domain AJAX requests.
    this.serverSideUrl = serverSideUrl;

    // This hash contains information as to whether each $.ajax parameter should be submitted to $.ajax directly, or passed to the CorsAway server.
    // true means that the parameter should be passed to the CorsAway server
    this.parameterIsForRemoteServer = {
//      accepts:        // not supported
//      async:          // not supported
        beforeSend:     false,              // submit to $.ajax
//      cache:          // not supported, see $.ajax documentation for how to implement
        complete:       false,              // submit to $.ajax
        contents:       false,              // submit to $.ajax
        contentType:    true,               // submit to remote server
        context:        false,              // submit to $.ajax
        converters:     false,              // submit to $.ajax
//      crossDomain:    // not supported
        data:           true,               // submit to remote server
        dataFilter:     false,              // submit to $.ajax
        dataType:       false,              // submit to $.ajax
        error:          false,              // submit to $.ajax
//      global:         // not supported
        headers:        true,               // submit to remote server
//      ifModified:     // not supported
//      isLocal:        // not supported
//      jsonp:          // not supported
//      jsonpCallback:  // not supported
        method:         true,               // submit to remote server
///     mimeType:       true,               // submit to remote server
///     password:       true,               // submit to remote server
//      processData:    // REQUIRES SPECIAL HANDLING: SEE COMMENTS IN CODE BELOW
//      scriptCharset:  // not supported
        statusCode:     false,              // submit to $.ajax
        success:        false,              // submit to $.ajax
        timeout:        false,              // submit to $.ajax
//      traditional:    // not supported
//      type:           // not supported
///     url:            true,               // submit to remote server
///     username:       true                // submit to remote server
//      xhr:            // not supported
//      xhrFields:      // not supported
    }

    // Use it just like $.ajax
    this.ajax = function (url, jqAjaxInfo) {
        //Redirect all requests to a call to the server

        // Sort jqAjaxInfo into parameters for $.ajax and for the remote server
        var localAjaxParams = {};
        var remoteHttpRequestParams = {};
        for(var k in jqAjaxInfo) {
            if(this.parameterIsForRemoteServer[k]) {
                // Submit it to the remote server
                remoteHttpRequestParams[k] = jqAjaxInfo[k];
            } else {        // some parameters are not supported; their behavior is undefined and doesn't matter
                // Submit it to $.ajax
                localAjaxParams[k] = jqAjaxInfo[k];
            }
        }

        // Prepare specially encapsulated data parameter for local $.ajax to submit to server-side CorsAway
        localAjaxParams.data = {
            dataToSubmit:               localAjaxParams.data,
            remoteHttpRequestParams:    remoteHttpRequestParams,
            remoteUrl:                  url
        };
        localAjaxParams.method = 'PUT'; // Always make request to CorsAway by PUT

        // Make call to $.ajax and pass info to server-side CorsAway service
        $.ajax(this.serverSideUrl, localAjaxParams);
    }
}

// Instantiate global object with URL of server-side CorsAway service
window.corsAway = new CorsAway('/local/url/of/corsaway.php');

所以现在我使用window.corsAway.ajax代替$.ajax,结果完全相同.服务器端代理旨在从远程服务器返回数据,或将其收到的任何HTML错误传递回ajax.

So now instead of $.ajax I use window.corsAway.ajax with exactly the same results. The server-side proxy is designed to return the data from the remote server, or to pass through any HTML error it receives back to ajax.

编写名为CorsAway的实用程序似乎有些错误,但是,嘿.服务器端代理会检查域,并且只会将内容传递给已批准的域(现在只有Google),所以可能会出问题,对吗?有人告诉我是否可能出问题. :-)

Something seems very wrong about writing a utility called CorsAway, but hey. The server-side proxy checks the domain and only passes things through to approved domains (right now only Google) so what could go wrong, right? Somebody tell me if something could go wrong. :-)

这篇关于写入Google Spreadsheet API时,CORS预检失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆