Pregunta

I am using jquery-fileupload to allow users to upload files to an external service (Cloudinary to be more specific):

<input type='file' name='file' class='cloudinary-fileupload' 
  data-url='https://api.cloudinary.com/v1_1/wya/auto/upload' />
<script>
  $('.cloudinary-fileupload').fileupload();
</script>

Since it is an external target, the browser initiates a CORS request. However, I noticed that the browser prepends a CORS preflight request. http://www.html5rocks.com/en/tutorials/cors/ gives pretty good insights about when a preflight request is triggered and when not. As far as I see, my request fulfills all criteria for being a CORS simple request (see section 'Types of CORS requests').

The file upload request that is sent to the external service:

POST /v1_1/wya/image/upload HTTP/1.1
Host: api.cloudinary.com
Connection: keep-alive
Content-Length: 22214
Accept: */*
Origin: http://wya.herokuapp.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarym73rCIa6t8eTNkTa
Referer: http://wya.herokuapp.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2

The additional preflight request which is sent to the external service prior to the file upload request:

OPTIONS /v1_1/wya/image/upload HTTP/1.1
Host: api.cloudinary.com
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://wya.herokuapp.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://wya.herokuapp.com/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: sv-SE,sv;q=0.8,en-US;q=0.6,en;q=0.4,de;q=0.2

Is there a way to avoid this extra preflight request? As far as I see it, the file upload request is a CORS simple request as it is an HTTP POST with Content-Type multipart/form-data and only simple request HTTP headers.


The reason why I want to get rid of the extra preflight request is that Cloudinary sends an HTTP 302/304 redirect as a response to the file upload. Browsers do not follow those redirects. Chrome fails with the following message:

XMLHttpRequest cannot load https://api.cloudinary.com/v1_1/wya/image/upload. 
The request was redirected to 'http://wya.herokuapp.com/upload?bytes=21534&created_at=2014-02-12T09%3A04%3…d5b62ebb92b9236e5be6d472df242d016&type=upload&version=1392195882&width=723', 
which is disallowed for cross-origin requests that require preflight. 
¿Fue útil?

Solución

The problem is that the XHR header is not sent with the request to Cloudinary which causes Cloudinary to redirect (IE fallback) instead of returning the JSON. This is usually caused because of improper initialization of the widget. You usually don't need to call $('.cloudinary-fileupload').fileupload() yourself as this is done by the included Javascript. If you still need to initialize the widget manually, please use $('.cloudinary-fileupload').cloudinary_fileupload().

Otros consejos

For those interested in javascript fetch. Here is the code that works for cloudinary upload. The following is for a react component, but the fetch should work in just about any javascript code. I also do have an nginxserver configured but that only does a proxy pass. The imp points to note are, use a FormData object to set upload_preset and file parameters. Avoid the headers and do a simple post.

export const uploadImg = (id, key, blob) => {
const controller = new AbortController();
const frmData = new FormData();
const apptype = blob.type;

frmData.set('upload_preset', '<upload_preset_name>');
frmData.set('public_id', id + '_' + key);
frmData.set('tags', id);
frmData.set('file', blob, key);
frmData.set('folder', '<folder_name>');

// Please note that headers is not being used. I tried using the headers they did //not work Commenting out these headers worked.

/* 
     const headers = new Headers({
        'Access-Control-Request-Headers':'Accept, Content-Type',
        'Accept': 'multipart/form-data',
        'Content-Type': 'multipart/form-data',        

    });  */


const uri = 'https://api.cloudinary.com/v1_1/<cloud_name>/image/upload';
const req = new Request(uri, {
    signal: controller.signal,
    method: 'POST',
    // mode:'no-cors',
    // headers: headers,
    body: frmData,
});

return fetch(req);enter code here
}

Cloudinary must really include standard best practice code samples for curl, fetch and axios. Developers end up wasting a lot of time trying to figure out and dealing with all the cors related issues.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top