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.
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
});
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.
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).
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.
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.
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.
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:
So now instead of
$.ajax
I usewindow.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.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. :-)
I haven't tried writing to Sheets on my project yet, but I've been bedeviled by exactly the same error on reading from the worksheets feed. I solved it by adding a ?callback parameter to the url. This is totally weird and I don't understand why it worked, b ut it seems to be a particularity of Chrome.
I saw another solution that recommended having a callback function callbackFunction defined in global scope that just returns true. I played around a bit and found that ?callback= calls a function, must be in global (window) scope but doesn't have to be defined all the way up top, it's just fine to assign it to window.callbackFunc right before the ajax call, and it passes the text response to the callback. So:
totally works. My CORS problems went away when I added that callback parameter to the URL. So now I'm using window.callbackInGlobalScopeWithAVeryLongNameBecauseIMakeALotOfDifferentAjaxCallsInMyApplication instead of the $.ajax({success: ...}) option, but that may just be life in the ajax lane.
I don't understand why it works and I don't know if it will work with write operations or if it is specific to the worksheets feed. I did NOT get this error reading from the spreadsheets feed, so there's something going on fishy. What I'm working on is kind of a side project that I do instead of knitting, so one day in the future I'll try it with a write operation and we'll see what happens. Just wanted to offer this admittedly bizarre idea for now.
Updated
I know this is not a answer for your question, but I just found answer for my issue my own. I have updated my ajax call from
to
Removed GData-Version header.
Initial
I am having the same issue. I think this is a issue introduced in last couple of days because for me this use to work last week.