srgbnd
srgbnd

Reputation: 5614

Can't access POST data in HTTP server

I'm developing a tiny HTTP server to use in unit tests. The code is below.

Why the body value is available in req.on() but not in res.end()?

Reproduce

  1. Run server
const WebhookServer = require('./webhook_server');

const server = new WebhookServer();
server.listen();
  1. Run client
$ curl -XPOST http://localhost:1088 -d '{"num":1}'
{"method":"POST","body":"","type":"test"}
  1. Server log
last body:
body: {"num":1}
last body:
body: {"num":1}

Server code

const http = require('http')
const kill = require('kill-port');

class WebhookServer {
  constructor({ port = 1088, host = 'localhost' } = {}) {
    this.port = port;
    this.host = host;
  }

  listen() {
    this.server = http.createServer((req, res) => {
      if (['POST', 'PUT'].includes(req.method)) {
        let body = '';
        req.on('data', (data) => {
            body += data;
            console.log('body:', body);
        });

        res.writeHead(200, { 'Content-Type': 'application/json' });
        console.log('last body:', body);
        res.end(JSON.stringify({ method: req.method, body, type: 'test' }));
      } else { // GET, DELETE
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ method: req.method, type: 'test' }));
      }
    });

    this.server.listen(this.port, this.host);
  }

  kill() {
    return kill(this.port);
  }
}

module.exports = WebhookServer;

Upvotes: 0

Views: 43

Answers (1)

planet_hunter
planet_hunter

Reputation: 3966

You need to let the server finish reading incoming data.

As req is a readable stream, if you do res.end in req.on("end") event handler, it should work.

Check following code that worked for me -

const http = require('http')
const kill = require('kill-port');

class WebhookServer {
    constructor({ port = 1088, host = 'localhost' } = {}) {
        this.port = port;
        this.host = host;
    }

    listen() {
        this.server = http.createServer((req, res) => {
            if (['POST', 'PUT'].includes(req.method)) {
                let body = '';
                req.on('data', (data) => {
                    body += data;
                    console.log('body:', body);
                });
                // wait for the reading process to finish
                req.on("end", () => {
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    console.log('last body:', body);
                    res.end(JSON.stringify({ method: req.method, body, type: 'test' }));
                })

            } else { // GET, DELETE
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ method: req.method, type: 'test' }));
            }
        });

        this.server.listen(this.port, this.host, () => {
            console.log("started!");            
        });
    }

    kill() {
        return kill(this.port);
    }
}

module.exports = WebhookServer;

Request curl -XPOST http://localhost:1088 -d '{"num":1}'

Output {"method":"POST","body":"{\"num\":1}","type":"test"}

Upvotes: 2

Related Questions