azure-function-express icon indicating copy to clipboard operation
azure-function-express copied to clipboard

Content-Type doesn't work correctly

Open ghost opened this issue 7 years ago • 7 comments

I'm trying to make POST request and send JSON data to Azure Function using application/json Content-Type. But the function call hangs and return timeout instead of result.

App has the following configuration

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

Locally such expressjs application works perfectly. But looks like some trouble with Content-Type on Azure.

However when I change configuration to this one

app.use(bodyParser.json({ type: 'application/*+json' }));
app.use(bodyParser.urlencoded({ extended: true }));

My POST requests pass. But for x-www-form-urlencoded it still can't parse the data and returns timeout.

Could you please help me to understand why it doesn't work? Thank you

ghost avatar Apr 27 '18 05:04 ghost

app.use((req, res, next) => {
  req.get('Content-Type'); // it returns application/json
});

But this one doesn't work

app.use(bodyParser.json());
---- OR ----
app.use(bodyParser.json({ type: 'application/json' }));

ghost avatar Apr 27 '18 06:04 ghost

So, comparing local execution with azure, I can say that req object is stream object locally, and it should be a stream on azure, but it doesn't. And that's why bodyParser can't read stream and parse incoming data...

ghost avatar Apr 27 '18 17:04 ghost

When I started with this library my first test is doing a post. I couldn't figure out why it was hanging. A search found your issue and I was saved by using application/*+json. I dont really know why that works but it works so thanks!

Now I am testing file upload which was using bodyparser with type application/octet-stream and multer it is not working either. Not sure if this is related to content type again or something else. Did you ever find a solution?

spacem avatar Jun 21 '18 07:06 spacem

application/*+json is not actually the way. I did some trick to manage bodyParser stuff.

if (process.env.CLOUD === 'azure') { // For azure cloud apply specific body parser
  app.use(azureBodyParser());
} else {
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: true }));
}

So here I check first the environment. If it's not azure then just follow usual express bodyParser style. For azure environment I created custom middleware to handle request object.

'use strict';

const queryString = require('query-string');

/**
 * Azure body parser
 */
function azureBodyParser() {
  return function(req, res, next) {
    // x-www-form-urlencoded
    if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
      req.body = queryString.parse(req.body, { arrayFormat: 'bracket' });
    } 

    next();
  };
}

module.exports = azureBodyParser;

This can be different. You can add more checks if you want. So basically for application/json content-type azure itself fulfill req.body object with proper request data as json object. For application/x-www-form-urlencoded content-type data comes in raw format, so I used query-string library to parse incoming data and fulfill req.body with json object.

For your case with multer I didn't try anything actually. I assume data will come as buffer object, and you should add one more check for content-type application/octet-stream and parse it by yourself, maybe using some existing libraries. But I'm not sure, you better try yourself, I may be wrong.

ghost avatar Jun 21 '18 08:06 ghost

I opened a PR which changes the IncomingMessage (wrapped req object) to be a Readable stream with the rawBody pushed. This seems to fix this issue

dcollien avatar Mar 06 '19 10:03 dcollien

Thanks @dcollien . Hope it will.

Here is some useful information about this ticket I've found so far https://stackoverflow.com/questions/50043746/azure-function-doesnt-respond-if-content-type-application-json

ghost avatar Mar 06 '19 11:03 ghost

@iredjee I think it might not so much to do with the content-type, but the same cause as #22 - if the request object isn't a stream, then it can't pipe the original request body into a stream-consuming JSON parser. The original code just did a NOOP if it tried to be used as a stream - hence why it might have just timed out. Changing the request object to extend a stream (as it is in express) might be the fix (I hope).

edit: if you'd like to try it out, you can change your package.json to use:

  "dependencies": {
    "azure-function-express": "github:dcollien/azure-function-express#dist"
  }

dcollien avatar Mar 07 '19 04:03 dcollien