最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to get arraysobjects sent via form in sails.js (with enctype multipartform-data) - Stack Overflow

programmeradmin0浏览0评论

I'm nesting information in my forms to match my models, this greatly simplify things on the backend, but I can't find out how to get arrays or objects (or the bination of both) in Sails.js

Assuming I have a form like this

NOTE: Support for "multipart/form-data" is totally required.

<form action="/articles" method="post" enctype="multipart/form-data">
    <input type="file" name="status" value="published">
    <!-- Entry 0 -->
    <input(type="text" name="entries[0][title]" value="Entry 1")
    <input(type="text" name="entries[0][content]" value="Entry 1 Content...")
    <!-- Entry 1 -->
    <input(type="text" name="entries[1][title]" value="Entry 2")
    <input(type="text" name="entries[1][content]" value="Entry 2 Content...")
    <!-- images -->
    <input type="file" name="images[]">
    <input type="file" name="images[]">
</form>

Im expecting to get an object like this in the req.params.all() obj

{
 status: 'published',
 entries: [
   {title: 'Entry 1', content: 'Entry 1 Content...'},
   {title: 'Entry 2', content: 'Entry 2 Content...'}
 ]
}

Now when calling req.params.all()/req.body what I'm getting instead is:

{
 status: 'published',
 'entries[0][title]': 'Entry 1'
 'entries[0][content]': 'Entry 1 Content...'
 'entries[1][title]': 'Entry 2'
 'entries[1][content]': 'Entry 2 Content...'
 'entries[0][title]': 'Entry 1'
}

Calling req.file('images[]') gives the correct behavior. I'm checking the ._files property of what is returned by that fn and shows my 2 images in there. Using the brackets here seems really weird, but that's what it is.

I guess that related to what I'm getting with req.params.all() I can further parse this, but it'll be hacky and brittle if something changes in the future. In any case this is a mon pattern in any web app and supported by many languages and frameworks, so to me is really odd that it seems impossible to get what I need with just plain sails.js functionality, so i'm guessing that I'm not doing something as it should or that I'm missing something. Please point me out in the right direction, and if actually Sails does not support this basic nesting behaviour, then how should I proceed?

Sending raw content via Javascript is not an option here (Unless is impossible otherwise) as suggested in the third answer in this question: Is it possible in Sailsjs to build more plex models Doing it this way, at least for the text based fields I get the correct output, not sure with images, since I've tested via postman with rawdata.

Edit: So far i've tried changing the skipper body parser in config/http.js like this:

bodyParser: {
   fn: require('body-parser').urlencoded,
   options: {extended:true}
 }

But that made my server useless, it did start, but it didn't respond to any request, not sure why (Even using their our example with skipper, that you just have to unment, does not work).

Since skipper is based on bodyparser, I modified the skipper module index.js just to test what happens.

var URLEncodedBodyParser = connect.urlencoded({extended:true})

But it didn't work, I get the same result as the begining, even installing body-parser and using it instead of the connect.urlencoded body parser had no effect.

Edit 2: As @robertklep stated using form-data without multipart works, but of course I lose the ability to upload files, which is really important and the reason I put it in the example form.

Edit 3: Just to plement the accepted answer in case someone needs it, this is what I did:

In config/http.js

middleware: {  
     order: [
      // some middleware
      'bodyParser',
      'qsBodyParser',
      // more middleware
    ],
    qsBodyParser: require('../api/middleware/qsBodyParser')
}

And in api/middleware/qsBodyParser

Qs = require('qs');

qsBodyParser = function(req, res, next) {
  if req.is('multipart/form-data'){
   req.body = Qs.parse(req.body);
  }
  return next();
};

module.exports = qsBodyParser;

I'm nesting information in my forms to match my models, this greatly simplify things on the backend, but I can't find out how to get arrays or objects (or the bination of both) in Sails.js

Assuming I have a form like this

NOTE: Support for "multipart/form-data" is totally required.

<form action="/articles" method="post" enctype="multipart/form-data">
    <input type="file" name="status" value="published">
    <!-- Entry 0 -->
    <input(type="text" name="entries[0][title]" value="Entry 1")
    <input(type="text" name="entries[0][content]" value="Entry 1 Content...")
    <!-- Entry 1 -->
    <input(type="text" name="entries[1][title]" value="Entry 2")
    <input(type="text" name="entries[1][content]" value="Entry 2 Content...")
    <!-- images -->
    <input type="file" name="images[]">
    <input type="file" name="images[]">
</form>

Im expecting to get an object like this in the req.params.all() obj

{
 status: 'published',
 entries: [
   {title: 'Entry 1', content: 'Entry 1 Content...'},
   {title: 'Entry 2', content: 'Entry 2 Content...'}
 ]
}

Now when calling req.params.all()/req.body what I'm getting instead is:

{
 status: 'published',
 'entries[0][title]': 'Entry 1'
 'entries[0][content]': 'Entry 1 Content...'
 'entries[1][title]': 'Entry 2'
 'entries[1][content]': 'Entry 2 Content...'
 'entries[0][title]': 'Entry 1'
}

Calling req.file('images[]') gives the correct behavior. I'm checking the ._files property of what is returned by that fn and shows my 2 images in there. Using the brackets here seems really weird, but that's what it is.

I guess that related to what I'm getting with req.params.all() I can further parse this, but it'll be hacky and brittle if something changes in the future. In any case this is a mon pattern in any web app and supported by many languages and frameworks, so to me is really odd that it seems impossible to get what I need with just plain sails.js functionality, so i'm guessing that I'm not doing something as it should or that I'm missing something. Please point me out in the right direction, and if actually Sails does not support this basic nesting behaviour, then how should I proceed?

Sending raw content via Javascript is not an option here (Unless is impossible otherwise) as suggested in the third answer in this question: Is it possible in Sailsjs to build more plex models Doing it this way, at least for the text based fields I get the correct output, not sure with images, since I've tested via postman with rawdata.

Edit: So far i've tried changing the skipper body parser in config/http.js like this:

bodyParser: {
   fn: require('body-parser').urlencoded,
   options: {extended:true}
 }

But that made my server useless, it did start, but it didn't respond to any request, not sure why (Even using their our example with skipper, that you just have to unment, does not work).

Since skipper is based on bodyparser, I modified the skipper module index.js just to test what happens.

var URLEncodedBodyParser = connect.urlencoded({extended:true})

But it didn't work, I get the same result as the begining, even installing body-parser and using it instead of the connect.urlencoded body parser had no effect.

Edit 2: As @robertklep stated using form-data without multipart works, but of course I lose the ability to upload files, which is really important and the reason I put it in the example form.

Edit 3: Just to plement the accepted answer in case someone needs it, this is what I did:

In config/http.js

middleware: {  
     order: [
      // some middleware
      'bodyParser',
      'qsBodyParser',
      // more middleware
    ],
    qsBodyParser: require('../api/middleware/qsBodyParser')
}

And in api/middleware/qsBodyParser

Qs = require('qs');

qsBodyParser = function(req, res, next) {
  if req.is('multipart/form-data'){
   req.body = Qs.parse(req.body);
  }
  return next();
};

module.exports = qsBodyParser;
Share Improve this question edited Jul 14, 2017 at 14:40 Amiga500 6,14111 gold badges71 silver badges119 bronze badges asked Aug 13, 2015 at 3:38 Lu RomanLu Roman 2,2603 gold badges26 silver badges41 bronze badges 2
  • 1 body-parser doesn't handle multipart/form-data, which would explain why using it doesn't seem to change anything. – robertklep Commented Aug 13, 2015 at 7:59
  • I was thinking about that last night, and checked today without the multipart, and indeed it parses correctly, but i need it to work with multipart/form-data – Lu Roman Commented Aug 13, 2015 at 15:42
Add a ment  | 

1 Answer 1

Reset to default 7

The currect version of skipper depends on [email protected], which depends on [email protected], which doesn't handle the way you are sending form arrays/objects.

Your form example es out like this (using extended : true):

{
  "entries" : [{
    "content" : "Entry 1 Content..."
  }, {
    "content" : "Entry 2 Content..."
  }]
}

The latest version ([email protected]) works as expected, so you have to plug that into skipper somehow.

EDIT: this ment seems to suggest that using multipart/form-data will disable array(/object?) parsing altogether.

EDIT #2: you can manually parse req.body using qs, which seems to accept an object as argument:

var qs  = require('qs');

var obj = qs.parse({
 status: 'published',
 'entries[0][title]': 'Entry 1',
 'entries[0][content]': 'Entry 1 Content...',
 'entries[1][title]': 'Entry 2',
 'entries[1][content]': 'Entry 2 Content...',
});

// obj is now:
// { status: 'published',
//   entries:
//    [ { title: 'Entry 1', content: 'Entry 1 Content...' },
//      { title: 'Entry 2', content: 'Entry 2 Content...' } ] }
发布评论

评论列表(0)

  1. 暂无评论