2

am trying to upload to a Cloudinary server directly from my client so i could track the progress of the upload but the problem is that when i trigger the post request it always gets

"Access to XMLHttpRequest at 'https://api.cloudinary.com/v1_1/[cloudName]/image/upload' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response"

when i tried the same code in my friend's project it worked fine but for me it doesn't which is weird i didn't know where the problem is coming from

my upload function :

     uploadPhotos() {

this.coverPhotoFormData.append("file", this.coverPhotoFile);
this.coverPhotoFormData.append("upload_preset",[PresetName]);
const req = new HttpRequest('POST', 'https://api.cloudinary.com/v1_1/[CloudName]/image/upload', 
  this.coverPhotoFormData, {
  reportProgress: true,
});

this.http.request(req).subscribe(event => {
  let total = 0;
  if (event.type === HttpEventType.UploadProgress) {
    const percentDone = Math.round(100 * event.loaded / event.total);
    console.log(percentDone)
  } else if (event instanceof HttpResponse) {

  }

});
}
AOUADI Slim
  • 299
  • 1
  • 8
  • 27
  • Cors errors usually pop up on poorly configured servers. Is there a possiblity to set cors on the cloudinary server? Maybe this answer could support u --> https://stackoverflow.com/questions/32500073/request-header-field-access-control-allow-headers-is-not-allowed-by-itself-in-pr – sagat Jul 30 '20 at 15:02
  • @sagat it appears the problem came from my chrome browser because i tested this code in OperaGX and it worked perfectly if you have any idea how to solve this problem tell me – AOUADI Slim Jul 30 '20 at 15:06
  • I would suggest to you to inspect the preflight request and the needed headers on it in the chrome dev tools. Chrome is state of the art. Regardless of Opera working only little percentage of users use opera or anything else. regards – sagat Jul 30 '20 at 15:12

3 Answers3

0

If we send an OPTIONS request to Cloudinary we can check the related Access-Control headers.

curl -iX OPTIONS https://api.cloudinary.com/v1_1/cloud/image/upload

HTTP/1.1 200 OK
Access-Control-Allow-Headers: Cache-Control, Content-Disposition, Content-MD5, Content-Range, Content-Type, DPR, Viewport-Width, X-CSRF-Token, X-Prototype-Version, X-Requested-With, X-Unique-Upload-Id
Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS
Access-Control-Max-Age: 1728000
Cache-Control: no-cache
Content-Type: text/plain; charset=utf-8
Date: Thu, 30 Jul 2020 15:20:11 GMT
Server: cloudinary
Status: 200 OK
Vary: Accept-Encoding
X-Request-Id: 4b3cb7f430585a4bc27d3ce4e559ced1
X-UA-Compatible: IE=Edge,chrome=1
X-XSS-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive

Based on the error message you shared - Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response - your upload request has an 'authorization' header which isn't allowed for cross-origin requests because it's not listed under the response header Access-Control-Allow-Headers. You will want to double-check the request your configuration/code is making and ensure this header is not part of the upload call as it's not needed.

Below is the least amount of code needed for an upload request. It will upload a 1x1px image submitted as Base64 Data URI. (just replace <cloud_name> and <upload_preset>) -

var fd = new FormData();

fd.append("file", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=");
fd.append("upload_preset", "<upload_preset>");

fetch('https://api.cloudinary.com/v1_1/<cloud_name>/upload',
  {
    method: 'POST',
    body: fd
  }
);

You could try using the above in your upload function rather than the current code and see if it works. It would use the default headers.

Aleksandar
  • 1,385
  • 6
  • 13
  • i will try it now but what made me shocked is that the same that i posted worked for my friend but not me – AOUADI Slim Jul 30 '20 at 16:27
  • it worked but how can i track the progress if am gonna use fetch or which authorization do i need to set to make it work ? – AOUADI Slim Jul 30 '20 at 16:35
  • it there a way to solve this problem while i keep using http.request ? – AOUADI Slim Jul 30 '20 at 16:41
  • If your friend only used the code you shared in your question then one reason it may not work for you is if elsewhere in your code the header is being set (such as globally for all HttpRequests via http.defaults or interceptors). What you can try is to add in your HttpRequest the `headers` parameter which only has the Content-Type and see if that overrides any other configuration. For example, below `reportProgress: true` you would add `headers: new HttpHeaders({ 'Content-Type': 'multipart/formdata' })` – Aleksandar Jul 30 '20 at 17:42
  • okay i will try it and tell you what happend , thanks for your time ! – AOUADI Slim Jul 30 '20 at 19:27
  • yes it happens that my authInterceptor is adding the bearer token to that request in the Header but the problem is that even when i deleted it completely from my app.module.ts it stills goes to the interceptor how's that ?? – AOUADI Slim Jul 31 '20 at 03:21
0

You probably have a set of credentials (cookies) that are supposed to be attached to to every request you make to local server, and when you try to upload to cloudinary this credentials are attached to the request. Unfortunately, cloudinary isn't expecting such credientials, so it blocks your request. What you can do is attach

withcredentials:false

to your request

devleinad
  • 3
  • 3
0

With axios, you can use the default settings and also track the upload progress like in the example below:

export const uploadFile = (imageData) => {
  const data = new FormData();
  const cloudName = "your_cloud_name";

  data.append("file", imageData);
  data.append("upload_preset", "your_upload_preset_here"); // set up your upload_preset on cloudinary.

  return axios.post(`https://api.cloudinary.com/v1_1/${cloudName}/upload`, data, {
    onUploadProgress: ProgressEvent => {
      //track your progress here
      console.log(ProgressEvent.loaded / ProgressEvent.total * 100);
    }
  }).then((res) => {
    console.log(res.data.secure_url);
    return res.data.secure_url;
  }).catch(console.log);
}
Mbiplang Ardel
  • 546
  • 5
  • 18