上传文件并使用express

时间:2019-07-08 18:14:15

标签: node.js ajax express multer

我正在使用mongodbnodejsexpress。 我有一个表单,该表单发送post的请求,要求使用multer-gridfs上传文件。 在表单内部,我只有input用于上传文件,而hidden input用于csrf。该请求通过ajax发送。问题是我发送ajax请求时对csrf token的验证

上传图像表格

<form enctype='multipart/form-data' id="upload-file-form" enctype="multipart/form-data" >
    <input type="file" name="file" id="file">
    <input type="hidden" name="_csrf" value="<%= csrfToken %>">
</form>

AJAX

function upload_image(){
    console.log('upload image')
    var fd = new FormData($("#upload-file-form").get(0));
    console.log(fd);
    var token = $('input[name="_csrf"]').val();

    $.ajax({
        url: '/posts/upload' ,
        data: {fd: fd, _csrf: token },
        dataType: 'json',
        type: 'POST',
        processData: false,
        contentType: false,
        success: function (response) {
            console.log(response);
        },
        error: function (xhr, status, error) {
            console.log('Error: ' + error.message);
        }
    })
}

错误

ForbiddenError: invalid csrf token
    at csrf (/home/pero/motoWebApp/node_modules/csurf/index.js:112:19)
    at Layer.handle [as handle_request] (/home/pero/motoWebApp/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/pero/motoWebApp/node_modules/express/lib/router/index.js:317:13)
    at /home/pero/motoWebApp/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/home/pero/motoWebApp/node_modules/express/lib/router/index.js:335:12)
    at next (/home/pero/motoWebApp/node_modules/express/lib/router/index.js:275:10)
    at Immediate.<anonymous> (/home/pero/motoWebApp/node_modules/express-session/index.js:495:7)
    at runCallback (timers.js:706:11)
    at tryOnImmediate (timers.js:676:5)
    at processImmediate (timers.js:658:5)

监听AJAX请求的路由

const GridFsStorage             = require('multer-gridfs-storage'),
      multer                    = require('multer');

const mongoURI = "mongodb://localhost:27017/app";

// Create storage engine
const storage = new GridFsStorage({
  url: mongoURI,
  file: (req, file) => {
    return new Promise((resolve, reject) => {
      crypto.randomBytes(16, (err, buf) => {
        if (err) {
          return reject(err);
        }
        const filename = buf.toString('hex') + path.extname(file.originalname);
        const fileInfo = {
          filename: filename,
          bucketName: 'uploaded_images' //collection name
        };
        resolve(fileInfo);
      });
    });
  }
});
const upload = multer({
    storage: storage,
});


router.post('/posts/upload', upload.single('file'), function(req, res){ 
    res.send(JSON.stringify(req.file.filename))
});

我看到要通过csrf验证ajax令牌,您必须在ajax请求的data属性内指定它,而我做到了。我认为问题是由属性processDatacontentType引起的 设置为false

如果我删除这些属性,则代码不会引发invalid csrf token错误,但在浏览器中它将显示TypeError: 'append' called on an object that does not implement interface FormData.

1 个答案:

答案 0 :(得分:0)

我发现,要上传图像并验证csrf令牌,而不是在csrf调用的data属性内传递ajax令牌,则应将其设置在内部header调用的ajax属性

您必须执行类似的操作

var form = $("#upload-file-form");
var fd = new FormData(form.get(0));
var token = $("#upload-file-form input[name='_csrf']").val();
$.ajax({
        url: '/posts/upload' ,
        headers: {"X-CSRF-TOKEN": <your token>},
        data: {your datas},
        dataType: 'json',
        type: 'POST',
        processData: false,
        contentType: false
   });