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());
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.