Search code examples
node.jsajaxpostkoa2

Access POST data in node using koa-body and koa-router


Making a ajax POST from a User Agent

$.ajax({
            type: 'POST',
            url: 'https://mysub.domain.dev/myroute',

            headers: {
              'X-Requested-With': 'XMLHttpRequest'
            },
            contentType: 'application/octet-stream; charset=utf-8',
            success: function(result) {
              successAction();
            },
            processData: false,
            data: myResult['myValue']
          });

With Koa2 on my server, how do I get the data myResult['myValue'] from the POST body?

const bodyParser = require('koa-body');

const router = new Router();
const body = bodyParser();


router.post('/myroute/', body, async (ctx, next) => {

const getMyValue = ctx.request.body.data.myValue;

}

I've tried various combinations. All are undefined or empty objects.

const getMyValue = ctx.request.body

Object{}

const getMyValue = ctx.request.body.data;

undefined

const getMyValue = ctx.request.body.myResult['myValue'];

undefined


Solution

  • Couple of things going on here.

    First, you need to explicitly tell koa-body to look for multipart form data (it's off by default). So:

    const koaBody = require('koa-body')
    
    router.post('/myroute', koaBody({ multipart: true }),
      async (ctx, next) => {
        // ctx.request.body.fields: additional (non-file) fields
        // ctx.request.body.files: files (octet-stream) 
      })
    

    Second, in the client you're probably going to want to set the enctype and explicitly set contentType to false. This seems counter-intuitive, but it stops jQuery from adding a ContentType header which will be missing a boundary string. Your request would look something like this:

    $('#go').click(evt => {
      evt.preventDefault()
    
      const data = new FormData($('#uploadForm')[0])
      data.append('extra', 'fields if required')
    
      $.ajax({
        contentType: false,
        data,
        enctype: 'multipart/form-data',
        processData: false,
        success: result => $('#result').text(result),
        type: 'POST',
        url: '...'
      })
    })
    

    Note that the FormData in the example might not fit your use case, it was just a convenient demonstration. It's likely you can simply use data: myresult['myValue'], assuming that's a file.