简体   繁体   中英

Azure Function doesn't respond if Content-Type application/json

Introduction

I have running Azure Function, which is written as Expressjs application. I have simple routes there to test

// Test get
router.get('/test', (req, res) => {
  return res.status(200).send({ result: req.query });
});

// Test post
router.post('/test', (req, res) => {
  return res.status(200).send({ result: req.body });
});

The app configuration is the following

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

Issue

I'm trying to do POST /test request.

With Content-Type: application/javascript it works well
With Content-Type: application/json it calls function, but nothing executes, and timeout is returned.

There is no issue with GET /test route.
There is no issue running locally.

Need help to understand why Azure Function call doesn't work properly for POST requests with Content-Type: application/json. Thank you

use :

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

to allow custom json types

Going deeper how Azure Function and body parser work, I figured out the root of the problem.

Be careful with request object

In regular expressjs app we have request object, which is actually instance of Stream object, and all incoming data goes through this streaming.

So, we have raw data, and we need to parse it right way. bodyParser middleware has several methods to parse this data from stream based on it's type (Content-Type).
For example bodyParser.json() method tries to parse data in JSON format with application/json content type. Once this function parses data req.body is fulfilled with JSON object.

Azure Functions don't support streaming

This is where everything breaks :) Yes, it doesn't support streaming. And since this is true data is accepted different way. So request object is no longer Stream object. And req.body is already fulfilled with incoming data. For application/json it contains JSON object, for other content types it contains raw data which is needed to be parsed. As example I can share my simple middleware code for parsing data with type x-www-form-urlencoded .

'use strict';

// https://github.com/sindresorhus/query-string
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;

Then use it like this

const app = require('express')();
const azureBodyParser = require('./middlewares/azureBodyParser');

// ...

app.use(azureBodyParser());

You can change it and add more handlers for other content types.
Also we need to provide some condition whether we run our app on server or as Azure Function, it's possible using ENV variables for example. It's your home task :)

The problem

Since Azure Functions don't support streaming, bodyParser.json() tries to get data from stream, and this is a point where app stuck. As a result function execution ends up with timeout.

Hope it will be helpful for all who struggling with Azure... Good luck :)

Might be late to this thread. Had a similar issue migrating an express app to Azure Functions and had to consume x-form-urlencoded values.

Used

const qs = require('qs');

While evaluating the request checked if the requst has rawBody and the relevant headers

if(req.rawBody)

and then simply

parsedBody = qs.parse(req.rawBody);}

Hope this helps someone.

It is a pain to host an Express API as is due to the discontinued support in Azure Functions for express

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM