Search code examples
reactjsaxioscorsfetchcloudinary

Axios post blocked by CORS. Using CLoudinary api


I am trying to do a post request with axios to upload a image to cloudinary from my frontend React app. I am getting this error from the axios code below:

http://localhost:3000 has been blocked by CORS policy: Request header field x-access-token is not allowed by Access-Control-Allow-Headers in preflight response.

Using axios, doesnt work gives me cors error

await axios({
  method: "POST",
  url: "https://api.cloudinary.com/v1_1/******/image/upload/",
  data: {
    file: img,
    upload_preset: "*****",
    cloud_name: "****",
  },
})
  .then((res) => {
    console.log("response");
    console.log(res);
  })
  .catch((err) => console.log(err));

Meanwhile when i use fetch using the same api request, the post request works and doesnt give me error. Anyone know why and how to call the api using axios?

  const data = new FormData();
        data.append("file", img);
        data.append("upload_preset", "*****");
        data.append("cloud_name", "*****");


  await fetch(
           "  https://api.cloudinary.com/v1_1/****/image/upload/",
           {
             method: "post",
             body: data,
           }
         )
           .then((resp) => resp.json())
           .then((data) => {
             setUrlArray((prevState) => [...prevState, data.url]);
           })
           .catch((err) => console.log(err));

Extra info: My upload preset is unsigned.
Also got this from the console after making the axios api call

{
error: {
message: "Upload preset must be specified when using unsigned upload"
}
}


Solution

  • To create an Axios request equivalent to your working fetch() one, you need to

    1. Craft a FormData instance and set it as the request data so your content-type is multipart/form-data

    2. Make sure you're not using a previously created Axios instance with unwanted default headers

    3. If custom headers have been set on the default Axios instance, eg

      axios.defaults.headers.common["x-access-token"] = TOKEN
      

      you may need to override / delete them in transformRequest

    4. To avoid any interceptors defined on the default Axios instance, create a new separate instance for un-intercepted requests

    import axios from "axios" // import the default instance
    
    // create a new instance without interceptors. 
    // you could also create this in its own module and import from there
    const instance = axios.create()
    
    const data = new FormData()
    data.append("file", img);
    data.append("upload_preset", "*****");
    data.append("cloud_name", "*****");
    
    const res = await instance.post(
      "https://api.cloudinary.com/v1_1/******/image/upload/", 
      data
    )
    

    Ideally, if your app is going to customise requests, you should always use an Axios instance (or multiple instances) to avoid messing around with the defaults.