expressjs / body-parser

Node.js body parsing middleware
MIT License
5.45k stars 727 forks source link

Body-parser `urlencoded` Not Parsing list of strings in Request Body Correctly #525

Closed WrathOP closed 4 months ago

WrathOP commented 5 months ago

Description:

I am experiencing an issue with body-parser when attempting to parse a URL-encoded JSON string in the request body. Despite using the body-parser.urlencoded() middleware, the JSON string is not being parsed correctly into an array of strings on the server.

Environment:

Steps to Reproduce:

  1. Install Dependencies:

    npm install express body-parser
  2. Backend Setup:

    const express = require('express');
    
    const app = express();
    
    // Use body-parser middleware to parse URL-encoded payloads
    app.use(express.urlencoded({ extended: false }));
    
    app.patch('/projects', (req, res) => {
      const filter = JSON.parse(req.query.filter);
      let update = req.body;
    
      console.log('Filter:', filter);
      console.log('Update:', update);
    
      // Handle the patch request here
      res.send('Project updated');
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
  3. Curl Command:

    curl --location --request PATCH 'http://localhost:3000/projects?filter=%7B%22projectCode%22%3A+%2200001638%22%7D' \
    --header 'Accept: */*' \
    --header 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \
    --header 'Connection: keep-alive' \
    --header 'Origin: http://localhost:50594' \
    --header 'Referer: http://localhost:50594/' \
    --header 'Sec-Fetch-Dest: empty' \
    --header 'Sec-Fetch-Mode: cors' \
    --header 'Sec-Fetch-Site: same-site' \
    --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36' \
    --header 'content-type: application/x-www-form-urlencoded; charset=utf-8' \
    --header 'sec-ch-ua: "Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"' \
    --header 'sec-ch-ua-mobile: ?0' \
    --header 'sec-ch-ua-platform: "macOS"' \
    --data-urlencode 'access=["8399BR", "8620MH"]'
  4. Expected Behavior: The access field should be parsed as an array of strings.

    {
        // other fields
     "access": ["8399BR", "8620MH"]
    }
  5. Actual Behavior: The access field is being stored as a single string:

    {
        // other fields
     "access": "[\"8399BR\",\"8620MH\"]"
    }
  6. Additional Information: The body-parser middleware is expected to parse URL-encoded data correctly, but it seems to struggle with parsing JSON strings into arrays. This issue significantly impacts my application as the data format is critical for backend processing. I have tried using body-parser.json(), but I am constrained to using application/x-www-form-urlencoded due to frontend requirements. Workaround: As a workaround, I manually parse the access field from a JSON string within the request handler, which is not ideal and clutters the route logic.

 if (update.access) {
        try {
          update.access = JSON.parse(update.access);
        } catch (e) {
          return res.status(400).send('Invalid access field');
        }
      }
  1. Request: I would appreciate it if the maintainers could investigate this issue and provide a fix or a recommended solution. Additionally, if there are any specific configurations or alternative approaches I should consider, please let me know.
WrathOP commented 5 months ago

I am dumb or this is anyways keep this issue as someone might find this useful

{
     // other fields
  "access": ["8399BR", "8620MH"]
}

is the output

image
WrathOP commented 5 months ago

Now the problem is how can I send it like this from the frontend, its flutter

http.patch method wants its body as a Map<string,string> and then converts that into FormData for the request.

So basically I would need to have a write custom encoding?

wesleytodd commented 4 months ago

With the code you provided (added one additional log to be sure) I ran this curl and it appeared to work correctly:

curl "http://localhost:3000/projects?filter=$(node -p 'encodeURIComponent(JSON.stringify({ projectCode: [1,2] }))')"
$ node index.js
Server is running on port 3000
Raw Filter: {"projectCode":[1,2]}
Filter: { projectCode: [ 1, 2 ] }
Update: {}

We do not provide general technical support on issues like this, but afaict this is not a bug in this package.

WrathOP commented 4 months ago

I guess I may have expressed myself unclearly. What I initially thought was a bug turned out to be an unusual implementation of how FormData handles arrays. The code snippet you showcased isn't related to my issue. The query is parsed correctly; the problem is actually with the form data. However, I don't want to bother the maintainers.

PS: I just realised how badly written my case is, no wonder he thought I was talking about the query not being parsed correctly.

wesleytodd commented 4 months ago

Haha, ok sorry for the confusion, but glad to see you are working it out.