首页 > 解决方案 > OPTIONS 404 on Vue.js file upload

问题描述

I have defined cors in my express app and don't have this issue with most of the routes. But, for a particular component that I use to upload images:

<input type="file" class="form-control" @change="imageChagned">

<div  @click="postPhoto">Upload Photo</div>  

methods:

postPhoto: function() {
    console.log('sending photo');
    axios.post( this.BASE_URL + "/profile/addphoto", {
    file: this.image 
    }, this.jwt).then( (res) => { 
    console.log('after photo sent');
    this.image = '';
    console.log(res);
    })
      .catch( (error) => { 

        console.log(error);

      });

},

imageChagned(e) { 
    var reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = (e) => {
            this.image = e.target.result;    
        }
    } 

I get this error in browser:

OPTIONS http://127.0.0.1:3000/profile/addphoto 404 (Not Found)
dispatchXhrRequest @ xhr.js?b50d:178
xhrAdapter @ xhr.js?b50d:12
dispatchRequest @ dispatchRequest.js?5270:59
Promise.then (async)
request @ Axios.js?0a06:51
Axios.(anonymous function) @ Axios.js?0a06:71
wrap @ bind.js?1d2b:9
postPhoto @ AddPhoto.vue?0625:242
invoker @ vue.runtime.esm.js?2b0e:2023
fn._withTask.fn._withTask @ vue.runtime.esm.js?2b0e:1822
addphoto:1 Access to XMLHttpRequest at 'http://127.0.0.1:3000/profile/addphoto' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

here is the router that receives the post:

  router.post('/addphoto',  checkAuth, (req, res)=> {

    console.log('add photo post received');
       let filename = Math.floor(Math.random() * 100000);
  let dir = './uploads/' + req.user.id;
    if (!fs.existsSync(dir)){
        fs.mkdirSync(dir);
    }   
    base64String = req.body.file;
    let str = base64String.split(';base64,');
    let base64Image = str[1];
    let extRaw = str[0];
    let ext = extRaw.split('/')[1].toLowerCase();
    let extArray = ['jpg', 'jpeg', 'png', 'gif'];
    const buffer = Buffer.from(base64String.substring(base64String.indexOf(',') + 1));
    fileSizeMB = buffer.length / 1e+6
    //Check file extension
    if (!extArray.includes(ext)) {
      res.status(403).json({msg: 'error: file extention not allowed'})
      return
    };

    //Check file size
    if(fileSizeMB > 5) {
      res.status(403).json({msg: 'error: file is too large'})
      return
    }

    let imgId =  filename + '.' + ext; 
    let filePath = dir + "/" + imgId;
    fs.writeFile( filePath, base64Image, {encoding: 'base64'}, function(err) {
      });
      const photoFields = {};
      photoFields.photos = []
      let p = {}

      p.imgId =  imgId  ;
      p.visible = 'all'
    User.findOne({ _id: req.user.id }).then(user => {
      if (!user.images.profileImg.length > 0 ) {
        user.images.profileImg = p.imgId;
      }

      user.images.photos.push(p);
      user.save().then(()=>{
        console.log('new photo is saved');
        res.json({ images: user.images });
      }).catch(err =>
      console.log(err)
      );

    });


  });

This problem bugs me for hours so really appreciate your hints to fix it.

The odd thing is that the component was working fine but it ceased to work after some small changes that I've made to my code.

标签: javascriptnode.jsexpressvue.jsaxios

解决方案


As the error indicates, there is no endpoint called /profile/addphoto for method OPTIONS. The route you posted would not be hit by an OPTIONS request, since you specified that it only receives POST.

The OPTIONS request is used to let the requester know how it is allowed to use your API, so simply return status 200 after setting the cors headers. I usually do it by adding this to intercept any OPTIONS request made to the API. Just add it somewhere in the beginning of the routing:

app.use(function(req, res, next) {
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Access-Control-Allow-Headers', 'Origin, Accept, Content-Type, X-Requested-With, auth_token, X-CSRF-Token, Authorization');
    res.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT, PATCH');
    res.set('Access-Control-Allow-Credentials', 'true');

    // intercept OPTIONS method
    if (req.method === 'OPTIONS') {
        return res.status(200).end();
    }

    next();
});

推荐阅读